From bc3c4e76d704ec397c993904f3ff8240d887a4ba Mon Sep 17 00:00:00 2001 From: msweet Date: Fri, 10 May 2013 18:56:23 +0000 Subject: [PATCH] Import cups.org releases git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/tags/release-1.1.7@4306 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES.txt | 1427 + CREDITS.txt | 26 + ENCRYPTION.txt | 138 + INSTALL.txt | 157 + LICENSE.html | 895 + Makedefs.in | 169 + Makefile | 147 + README.txt | 276 + backend/Makefile | 141 + backend/betest.c | 85 + backend/ipp.c | 614 + backend/lpd.c | 673 + backend/parallel.c | 623 + backend/serial.c | 856 + backend/socket.c | 343 + backend/usb.c | 437 + berkeley/Makefile | 105 + berkeley/lpc.c | 481 + berkeley/lpq.c | 539 + berkeley/lpr.c | 425 + berkeley/lprm.c | 269 + cgi-bin/Makefile | 121 + cgi-bin/admin.c | 1598 + cgi-bin/cgi.h | 87 + cgi-bin/classes.c | 360 + cgi-bin/html.c | 89 + cgi-bin/ipp-var.c | 299 + cgi-bin/ipp-var.h | 55 + cgi-bin/jobs.c | 139 + cgi-bin/printers.c | 360 + cgi-bin/template.c | 499 + cgi-bin/var.c | 672 + conf/Makefile | 73 + conf/classes.conf | 89 + conf/client.conf | 65 + conf/cupsd.conf | 639 + conf/mime.convs | 78 + conf/mime.types | 155 + conf/printcap | 2 + conf/printers.conf | 96 + config.h.in | 152 + configure.in | 670 + cups.dsw | 29 + cups.list | 320 + cups.sh.in | 143 + cups.spec | 179 + cups/Makefile | 170 + cups/cups.dsp | 188 + cups/cups.h | 175 + cups/cups_C.h | 133 + cups/debug.h | 57 + cups/dest.c | 546 + cups/emit.c | 410 + cups/encode.c | 311 + cups/http.c | 2042 + cups/http.h | 342 + cups/ipp.c | 1874 + cups/ipp.h | 430 + cups/language.c | 407 + cups/language.h | 222 + cups/mark.c | 441 + cups/md5.c | 392 + cups/md5.h | 94 + cups/md5passwd.c | 148 + cups/options.c | 420 + cups/page.c | 189 + cups/ppd.c | 1939 + cups/ppd.h | 268 + cups/snprintf.c | 287 + cups/string.c | 125 + cups/string.h | 94 + cups/tempfile.c | 200 + cups/testhttp.c | 124 + cups/testmime.dsp | 102 + cups/testppd.c | 198 + cups/testppd.dsp | 102 + cups/usersys.c | 447 + cups/util.c | 1680 + data/HPGLprolog | 37 + data/Makefile | 107 + data/classified | 277 + data/confidential | 277 + data/cups.pam | 2 + data/cups.suse | 2 + data/iso-8859-1 | 251 + data/iso-8859-10 | 251 + data/iso-8859-13 | 251 + data/iso-8859-14 | 251 + data/iso-8859-15 | 251 + data/iso-8859-2 | 253 + data/iso-8859-3 | 244 + data/iso-8859-4 | 251 + data/iso-8859-5 | 251 + data/iso-8859-6 | 206 + data/iso-8859-7 | 246 + data/iso-8859-8 | 214 + data/iso-8859-9 | 251 + data/psglyphs | 1051 + data/secret | 277 + data/standard | 261 + data/testprint.ps | 522 + data/topsecret | 277 + data/unclassified | 277 + data/utf-8 | 38 + data/windows-1250 | 254 + data/windows-1251 | 258 + data/windows-1252 | 254 + data/windows-1253 | 243 + data/windows-1254 | 252 + data/windows-1255 | 236 + data/windows-1256 | 259 + data/windows-1257 | 247 + data/windows-1258 | 250 + data/windows-874 | 228 + doc/Makefile | 230 + doc/cmp.html | 678 + doc/cmp.pdf | Bin 0 -> 54628 bytes doc/cmp.shtml | 595 + doc/cups.css | 4 + doc/cupsdoc.css | 9 + doc/documentation.html | 81 + doc/figures.sc | Bin 0 -> 75144 bytes doc/glossary.shtml | 73 + doc/idd.html | 1086 + doc/idd.pdf | Bin 0 -> 68356 bytes doc/idd.shtml | 1429 + doc/images/accept-jobs.gif | Bin 0 -> 259 bytes doc/images/add-class.gif | Bin 0 -> 242 bytes doc/images/add-printer.gif | Bin 0 -> 252 bytes doc/images/cancel-job.gif | Bin 0 -> 248 bytes doc/images/cancel-jobs.gif | Bin 0 -> 255 bytes doc/images/cancel.gif | Bin 0 -> 210 bytes doc/images/classes.gif | Bin 0 -> 591 bytes doc/images/config-printer.gif | Bin 0 -> 296 bytes doc/images/continue.gif | Bin 0 -> 224 bytes doc/images/cups-bar.gif | Bin 0 -> 1242 bytes doc/images/cups-block-diagram.gif | Bin 0 -> 11637 bytes doc/images/cups-large.gif | Bin 0 -> 7457 bytes doc/images/cups-medium.gif | Bin 0 -> 3163 bytes doc/images/cups-small.gif | Bin 0 -> 1266 bytes doc/images/delete-class.gif | Bin 0 -> 259 bytes doc/images/delete-printer.gif | Bin 0 -> 267 bytes doc/images/draft.gif | Bin 0 -> 926 bytes doc/images/hold-job.gif | Bin 0 -> 228 bytes doc/images/left.gif | Bin 0 -> 110 bytes doc/images/logo.gif | Bin 0 -> 1958 bytes doc/images/manage-classes.gif | Bin 0 -> 289 bytes doc/images/manage-jobs.gif | Bin 0 -> 266 bytes doc/images/manage-printers.gif | Bin 0 -> 296 bytes doc/images/modify-class.gif | Bin 0 -> 267 bytes doc/images/modify-printer.gif | Bin 0 -> 277 bytes doc/images/navbar.gif | Bin 0 -> 2869 bytes doc/images/navbar.xcf.gz | Bin 0 -> 4253 bytes doc/images/print-test-page.gif | Bin 0 -> 288 bytes doc/images/printer-idle.gif | Bin 0 -> 706 bytes doc/images/printer-processing.gif | Bin 0 -> 805 bytes doc/images/printer-stopped.gif | Bin 0 -> 794 bytes doc/images/reject-jobs.gif | Bin 0 -> 252 bytes doc/images/release-job.gif | Bin 0 -> 255 bytes doc/images/restart-job.gif | Bin 0 -> 249 bytes doc/images/right.gif | Bin 0 -> 145 bytes doc/images/show-active.gif | Bin 0 -> 303 bytes doc/images/show-completed.gif | Bin 0 -> 337 bytes doc/images/start-class.gif | Bin 0 -> 238 bytes doc/images/start-printer.gif | Bin 0 -> 255 bytes doc/images/stop-class.gif | Bin 0 -> 245 bytes doc/images/stop-printer.gif | Bin 0 -> 252 bytes doc/index.html | 36 + doc/ipp.html | 1434 + doc/ipp.pdf | Bin 0 -> 103091 bytes doc/ipp.shtml | 1926 + doc/overview.html | 500 + doc/overview.pdf | Bin 0 -> 37968 bytes doc/printing-overview.shtml | 125 + doc/references.shtml | 42 + doc/sam.html | 4634 ++ doc/sam.pdf | Bin 0 -> 243651 bytes doc/sam.shtml | 4317 ++ doc/sdd.html | 596 + doc/sdd.pdf | Bin 0 -> 64440 bytes doc/sdd.shtml | 564 + doc/spm.html | 7511 +++ doc/spm.pdf | Bin 0 -> 590490 bytes doc/spm.shtml | 8348 +++ doc/sps.html | 297 + doc/sps.pdf | Bin 0 -> 33691 bytes doc/sps.shtml | 457 + doc/ssr.html | 270 + doc/ssr.pdf | Bin 0 -> 31595 bytes doc/ssr.shtml | 167 + doc/stp.html | 262 + doc/stp.pdf | Bin 0 -> 35192 bytes doc/stp.shtml | 144 + doc/sum.html | 1643 + doc/sum.pdf | Bin 0 -> 95992 bytes doc/sum.shtml | 878 + doc/svd.html | 297 + doc/svd.pdf | Bin 0 -> 37808 bytes doc/svd.shtml | 212 + doc/system-overview.shtml | 19 + filter/Makefile | 207 + filter/common.c | 355 + filter/common.h | 70 + filter/form-main.c | 60 + filter/form-ps.c | 47 + filter/form-tree.c | 622 + filter/form.h | 175 + filter/hpgl-attr.c | 452 + filter/hpgl-char.c | 500 + filter/hpgl-config.c | 641 + filter/hpgl-input.c | 232 + filter/hpgl-main.c | 265 + filter/hpgl-polygon.c | 380 + filter/hpgl-prolog.c | 407 + filter/hpgl-vector.c | 731 + filter/hpgltops.h | 233 + filter/image-bmp.c | 510 + filter/image-colorspace.c | 882 + filter/image-gif.c | 644 + filter/image-jpeg.c | 194 + filter/image-photocd.c | 323 + filter/image-pix.c | 223 + filter/image-png.c | 250 + filter/image-pnm.c | 288 + filter/image-sgi.c | 267 + filter/image-sgi.h | 94 + filter/image-sgilib.c | 857 + filter/image-sun.c | 377 + filter/image-tiff.c | 1688 + filter/image-zoom.c | 310 + filter/image.c | 808 + filter/image.h | 231 + filter/imagetops.c | 861 + filter/imagetoraster.c | 4446 ++ filter/pstops.c | 944 + filter/raster.c | 252 + filter/raster.h | 233 + filter/rastertoepson.c | 1093 + filter/rastertohp.c | 806 + filter/textcommon.c | 1146 + filter/textcommon.h | 102 + filter/texttops.c | 1296 + fonts/AvantGarde-Book | Bin 0 -> 34871 bytes fonts/AvantGarde-BookOblique | Bin 0 -> 35156 bytes fonts/AvantGarde-Demi | Bin 0 -> 36354 bytes fonts/AvantGarde-DemiOblique | Bin 0 -> 36128 bytes fonts/Bookman-Demi | Bin 0 -> 44768 bytes fonts/Bookman-DemiItalic | Bin 0 -> 44950 bytes fonts/Bookman-Light | Bin 0 -> 44934 bytes fonts/Bookman-LightItalic | Bin 0 -> 44162 bytes fonts/Charter-Bold | Bin 0 -> 33799 bytes fonts/Charter-BoldItalic | Bin 0 -> 35229 bytes fonts/Charter-Italic | Bin 0 -> 35118 bytes fonts/Charter-Roman | Bin 0 -> 34869 bytes fonts/Courier | Bin 0 -> 45758 bytes fonts/Courier-Bold | Bin 0 -> 50493 bytes fonts/Courier-BoldOblique | Bin 0 -> 51527 bytes fonts/Courier-Oblique | Bin 0 -> 44404 bytes fonts/Helvetica | Bin 0 -> 36026 bytes fonts/Helvetica-Bold | Bin 0 -> 35941 bytes fonts/Helvetica-BoldOblique | Bin 0 -> 39013 bytes fonts/Helvetica-Narrow | Bin 0 -> 36615 bytes fonts/Helvetica-Narrow-Bold | Bin 0 -> 37240 bytes fonts/Helvetica-Narrow-BoldOblique | Bin 0 -> 38310 bytes fonts/Helvetica-Narrow-Oblique | Bin 0 -> 37247 bytes fonts/Helvetica-Oblique | Bin 0 -> 38314 bytes fonts/Makefile | 75 + fonts/NewCenturySchlbk-Bold | Bin 0 -> 48864 bytes fonts/NewCenturySchlbk-BoldItalic | Bin 0 -> 47083 bytes fonts/NewCenturySchlbk-Italic | Bin 0 -> 45832 bytes fonts/NewCenturySchlbk-Roman | Bin 0 -> 46830 bytes fonts/Palatino-Bold | Bin 0 -> 52406 bytes fonts/Palatino-BoldItalic | Bin 0 -> 51285 bytes fonts/Palatino-Italic | Bin 0 -> 50022 bytes fonts/Palatino-Roman | Bin 0 -> 52665 bytes fonts/Symbol | Bin 0 -> 33709 bytes fonts/Times-Bold | Bin 0 -> 44729 bytes fonts/Times-BoldItalic | Bin 0 -> 44656 bytes fonts/Times-Italic | Bin 0 -> 45458 bytes fonts/Times-Roman | Bin 0 -> 46026 bytes fonts/Utopia-Bold | Bin 0 -> 36580 bytes fonts/Utopia-BoldItalic | Bin 0 -> 37836 bytes fonts/Utopia-Italic | Bin 0 -> 37599 bytes fonts/Utopia-Regular | Bin 0 -> 36350 bytes fonts/ZapfChancery-MediumItalic | Bin 0 -> 49289 bytes fonts/ZapfDingbats | Bin 0 -> 45955 bytes locale/C/cups_C | 133 + locale/Makefile | 80 + locale/de/cups_de | 134 + locale/en/cups_en | 133 + locale/es/cups_es | 133 + locale/fr/cups_fr | 133 + locale/it/cups_it | 133 + locale/locale.txt | 32 + locale/translate.c | 259 + man/Makefile | 104 + man/accept.man | 60 + man/backend.man | 109 + man/classes.conf.man | 72 + man/cups-lpd.man | 92 + man/cups-polld.man | 46 + man/cupsd.conf.man | 246 + man/cupsd.man | 56 + man/enable.man | 67 + man/filter.man | 116 + man/lp.man | 156 + man/lpadmin.man | 140 + man/lpc.man | 80 + man/lpinfo.man | 60 + man/lpmove.man | 53 + man/lpoptions.man | 116 + man/lpq.man | 57 + man/lpr.man | 101 + man/lprm.man | 54 + man/lpstat.man | 130 + man/mime.convs.man | 54 + man/mime.types.man | 98 + man/printers.conf.man | 73 + pdftops/Array.cxx | 51 + pdftops/Array.h | 53 + pdftops/CNS13CMapInfo.h | 47771 +++++++++++++++ pdftops/COPYING | 339 + pdftops/Catalog.cxx | 301 + pdftops/Catalog.h | 73 + pdftops/CompactFontInfo.h | 464 + pdftops/Decrypt.cxx | 304 + pdftops/Decrypt.h | 49 + pdftops/Dict.cxx | 88 + pdftops/Dict.h | 69 + pdftops/Error.cxx | 50 + pdftops/Error.h | 26 + pdftops/FontEncoding.cxx | 143 + pdftops/FontEncoding.h | 64 + pdftops/FontFile.cxx | 1627 + pdftops/FontFile.h | 117 + pdftops/FontInfo.h | 2068 + pdftops/FormWidget.cxx | 129 + pdftops/FormWidget.h | 65 + pdftops/GB12CMapInfo.h | 50880 ++++++++++++++++ pdftops/GString.cxx | 223 + pdftops/GString.h | 95 + pdftops/Gfx.cxx | 2229 + pdftops/Gfx.h | 234 + pdftops/GfxFont.cxx | 1029 + pdftops/GfxFont.h | 240 + pdftops/GfxState.cxx | 2271 + pdftops/GfxState.h | 937 + pdftops/Japan12CMapInfo.h | 31362 ++++++++++ pdftops/Japan12ToRKSJ.h | 1038 + pdftops/Lexer.cxx | 468 + pdftops/Lexer.h | 72 + pdftops/Link.cxx | 630 + pdftops/Link.h | 336 + pdftops/Makefile | 134 + pdftops/Object.cxx | 222 + pdftops/Object.h | 300 + pdftops/OutputDev.cxx | 98 + pdftops/OutputDev.h | 140 + pdftops/PDFDoc.cxx | 251 + pdftops/PDFDoc.h | 125 + pdftops/PSOutputDev.cxx | 2261 + pdftops/PSOutputDev.h | 204 + pdftops/Page.cxx | 245 + pdftops/Page.h | 114 + pdftops/Params.cxx | 87 + pdftops/Params.h | 37 + pdftops/Parser.cxx | 209 + pdftops/Parser.h | 56 + pdftops/README | 348 + pdftops/SFont.h | 127 + pdftops/StdFontInfo.h | 546 + pdftops/Stream-CCITT.h | 459 + pdftops/Stream.cxx | 3478 ++ pdftops/Stream.h | 723 + pdftops/T1Font.h | 102 + pdftops/TTFont.h | 106 + pdftops/XRef.cxx | 592 + pdftops/XRef.h | 112 + pdftops/config.h | 118 + pdftops/configure.in | 203 + pdftops/gfile.cxx | 660 + pdftops/gfile.h | 132 + pdftops/gmem.c | 203 + pdftops/gmem.h | 53 + pdftops/gmempp.cxx | 31 + pdftops/gtypes.h | 31 + pdftops/parseargs.c | 190 + pdftops/parseargs.h | 71 + pdftops/pdftops.cxx | 275 + ppd/Makefile | 61 + ppd/deskjet.ppd | 198 + ppd/deskjet2.ppd | 217 + ppd/epson24.ppd | 128 + ppd/epson9.ppd | 126 + ppd/laserjet.ppd | 200 + ppd/okidat24.ppd | 128 + ppd/okidata9.ppd | 126 + ppd/stcolor.ppd | 132 + ppd/stphoto.ppd | 132 + pstoraster/Dependencies | 2213 + pstoraster/Fontmap | 98 + pstoraster/Makefile | 446 + pstoraster/bfont.h | 76 + pstoraster/bseq.h | 66 + pstoraster/btoken.h | 41 + pstoraster/ctype_.h | 37 + pstoraster/dirent_.h | 60 + pstoraster/dstack.h | 236 + pstoraster/errno_.h | 42 + pstoraster/errors.h | 148 + pstoraster/estack.h | 139 + pstoraster/files.h | 157 + pstoraster/fname.h | 54 + pstoraster/gconf.h | 43 + pstoraster/gconfig.c | 127 + pstoraster/gconfig.h | 243 + pstoraster/gconfig_.h | 5 + pstoraster/gconfigv.h | 4 + pstoraster/gdebug.h | 132 + pstoraster/gdev8bcm.h | 78 + pstoraster/gdevabuf.c | 404 + pstoraster/gdevbbox.c | 1069 + pstoraster/gdevbbox.h | 100 + pstoraster/gdevcmap.h | 74 + pstoraster/gdevcups.c | 3039 + pstoraster/gdevdbit.c | 708 + pstoraster/gdevddrw.c | 643 + pstoraster/gdevdflt.c | 270 + pstoraster/gdevdgbr.c | 586 + pstoraster/gdevhit.c | 98 + pstoraster/gdevht.h | 51 + pstoraster/gdevm1.c | 759 + pstoraster/gdevm16.c | 168 + pstoraster/gdevm2.c | 259 + pstoraster/gdevm24.c | 526 + pstoraster/gdevm32.c | 249 + pstoraster/gdevm4.c | 319 + pstoraster/gdevm8.c | 247 + pstoraster/gdevmem.c | 498 + pstoraster/gdevmem.h | 233 + pstoraster/gdevmgr.h | 127 + pstoraster/gdevmpla.c | 200 + pstoraster/gdevmrop.h | 97 + pstoraster/gdevnfwd.c | 797 + pstoraster/gdevpccm.h | 44 + pstoraster/gdevpcfb.h | 209 + pstoraster/gdevpcl.h | 52 + pstoraster/gdevpipe.c | 72 + pstoraster/gdevpm.h | 46 + pstoraster/gdevprn.c | 837 + pstoraster/gdevprn.h | 560 + pstoraster/gdevprna.h | 190 + pstoraster/gdevps.c | 1151 + pstoraster/gdevpsde.c | 282 + pstoraster/gdevpsdf.c | 514 + pstoraster/gdevpsdf.h | 292 + pstoraster/gdevpsdi.c | 349 + pstoraster/gdevpsdp.c | 705 + pstoraster/gdevpsds.c | 470 + pstoraster/gdevpsds.h | 110 + pstoraster/gdevpstr.h | 90 + pstoraster/gdevpxop.h | 114 + pstoraster/gdevvec.c | 905 + pstoraster/gdevvec.h | 349 + pstoraster/genarch.c | 163 + pstoraster/ghost.h | 34 + pstoraster/gp.h | 233 + pstoraster/gp_getnv.c | 60 + pstoraster/gp_nofb.c | 58 + pstoraster/gp_nsync.c | 120 + pstoraster/gp_unifn.c | 61 + pstoraster/gp_unifs.c | 424 + pstoraster/gp_unix.c | 173 + pstoraster/gpcheck.h | 65 + pstoraster/gpgetenv.h | 50 + pstoraster/gpsync.h | 81 + pstoraster/gs_btokn.ps | 313 + pstoraster/gs_ccfnt.ps | 100 + pstoraster/gs_cff.ps | 614 + pstoraster/gs_cidfn.ps | 466 + pstoraster/gs_cmap.ps | 256 + pstoraster/gs_cmdl.ps | 188 + pstoraster/gs_dbt_e.ps | 67 + pstoraster/gs_diskf.ps | 232 + pstoraster/gs_dpnxt.ps | 120 + pstoraster/gs_dps.ps | 205 + pstoraster/gs_dps1.ps | 147 + pstoraster/gs_dps2.ps | 200 + pstoraster/gs_epsf.ps | 67 + pstoraster/gs_fform.ps | 100 + pstoraster/gs_fonts.ps | 934 + pstoraster/gs_init.ps | 1521 + pstoraster/gs_iso_e.ps | 74 + pstoraster/gs_kanji.ps | 166 + pstoraster/gs_ksb_e.ps | 72 + pstoraster/gs_lev2.ps | 717 + pstoraster/gs_ll3.ps | 387 + pstoraster/gs_mex_e.ps | 72 + pstoraster/gs_mro_e.ps | 65 + pstoraster/gs_pfile.ps | 135 + pstoraster/gs_res.ps | 726 + pstoraster/gs_setpd.ps | 715 + pstoraster/gs_statd.ps | 301 + pstoraster/gs_std_e.ps | 81 + pstoraster/gs_sym_e.ps | 91 + pstoraster/gs_ttf.ps | 694 + pstoraster/gs_typ32.ps | 134 + pstoraster/gs_typ42.ps | 52 + pstoraster/gs_type1.ps | 145 + pstoraster/gs_wan_e.ps | 52 + pstoraster/gs_wl1_e.ps | 74 + pstoraster/gs_wl2_e.ps | 74 + pstoraster/gs_wl5_e.ps | 74 + pstoraster/gsalloc.c | 1621 + pstoraster/gsalloc.h | 87 + pstoraster/gsalpha.c | 48 + pstoraster/gsalpha.h | 41 + pstoraster/gsalphac.h | 71 + pstoraster/gsargs.c | 225 + pstoraster/gsargs.h | 89 + pstoraster/gsbitmap.h | 193 + pstoraster/gsbitops.c | 674 + pstoraster/gsbitops.h | 222 + pstoraster/gsbittab.c | 144 + pstoraster/gsbittab.h | 83 + pstoraster/gsccode.h | 72 + pstoraster/gsccolor.h | 58 + pstoraster/gscdefs.c | 78 + pstoraster/gscdefs.h | 81 + pstoraster/gscdevn.c | 184 + pstoraster/gschar.c | 1492 + pstoraster/gschar.h | 130 + pstoraster/gschar0.c | 407 + pstoraster/gscie.c | 1357 + pstoraster/gscie.h | 688 + pstoraster/gsclipsr.c | 45 + pstoraster/gsclipsr.h | 34 + pstoraster/gscolor.c | 357 + pstoraster/gscolor.h | 43 + pstoraster/gscolor1.c | 271 + pstoraster/gscolor1.h | 47 + pstoraster/gscolor2.c | 455 + pstoraster/gscolor2.h | 106 + pstoraster/gscolor3.c | 70 + pstoraster/gscolor3.h | 41 + pstoraster/gscompt.h | 59 + pstoraster/gscoord.c | 507 + pstoraster/gscoord.h | 55 + pstoraster/gscparam.c | 480 + pstoraster/gscpixel.c | 89 + pstoraster/gscpixel.h | 34 + pstoraster/gscpm.h | 39 + pstoraster/gscrd.c | 350 + pstoraster/gscrd.h | 75 + pstoraster/gscrdp.c | 631 + pstoraster/gscrdp.h | 104 + pstoraster/gscrypt1.h | 56 + pstoraster/gscscie.c | 374 + pstoraster/gscsel.h | 44 + pstoraster/gscsepnm.h | 54 + pstoraster/gscsepr.c | 352 + pstoraster/gscsepr.h | 74 + pstoraster/gscspace.c | 237 + pstoraster/gscspace.h | 400 + pstoraster/gsdcolor.h | 332 + pstoraster/gsdevice.c | 570 + pstoraster/gsdevice.h | 103 + pstoraster/gsdevmem.c | 239 + pstoraster/gsdll.h | 145 + pstoraster/gsdparam.c | 782 + pstoraster/gsdpnext.h | 34 + pstoraster/gsdps.h | 40 + pstoraster/gsdps1.c | 242 + pstoraster/gsdsrc.c | 121 + pstoraster/gsdsrc.h | 133 + pstoraster/gserror.h | 42 + pstoraster/gserrors.h | 56 + pstoraster/gsexit.h | 41 + pstoraster/gsfcmap.c | 167 + pstoraster/gsfcmap.h | 69 + pstoraster/gsflip.h | 46 + pstoraster/gsfont.c | 558 + pstoraster/gsfont.h | 87 + pstoraster/gsfont0.c | 136 + pstoraster/gsfunc.c | 78 + pstoraster/gsfunc.h | 136 + pstoraster/gsfunc0.c | 347 + pstoraster/gsfunc0.h | 66 + pstoraster/gsfunc3.c | 361 + pstoraster/gsfunc3.h | 114 + pstoraster/gsgc.h | 91 + pstoraster/gshsb.c | 171 + pstoraster/gshsb.h | 33 + pstoraster/gsht.c | 651 + pstoraster/gsht.h | 78 + pstoraster/gsht1.c | 449 + pstoraster/gsht1.h | 60 + pstoraster/gshtscr.c | 574 + pstoraster/gshtx.h | 158 + pstoraster/gsimage.c | 326 + pstoraster/gsimage.h | 84 + pstoraster/gsimpath.c | 191 + pstoraster/gsinit.c | 79 + pstoraster/gsio.h | 66 + pstoraster/gsiodev.c | 318 + pstoraster/gsiparam.h | 289 + pstoraster/gsiparm2.h | 63 + pstoraster/gsiparm3.h | 67 + pstoraster/gsiparm4.h | 59 + pstoraster/gsjconf.h | 81 + pstoraster/gsjmorec.h | 59 + pstoraster/gslib.h | 44 + pstoraster/gsline.c | 340 + pstoraster/gsline.h | 75 + pstoraster/gslparam.h | 52 + pstoraster/gsmalloc.c | 398 + pstoraster/gsmalloc.h | 78 + pstoraster/gsmatrix.c | 455 + pstoraster/gsmatrix.h | 80 + pstoraster/gsmdebug.h | 54 + pstoraster/gsmemlok.h | 64 + pstoraster/gsmemory.c | 198 + pstoraster/gsmemory.h | 277 + pstoraster/gsmemraw.h | 181 + pstoraster/gsmisc.c | 942 + pstoraster/gsnorop.c | 119 + pstoraster/gspaint.c | 356 + pstoraster/gspaint.h | 38 + pstoraster/gsparam.c | 382 + pstoraster/gsparam.h | 505 + pstoraster/gsparams.c | 417 + pstoraster/gsparams.h | 77 + pstoraster/gspath.c | 518 + pstoraster/gspath.h | 98 + pstoraster/gspath1.c | 480 + pstoraster/gspath2.h | 40 + pstoraster/gspcolor.c | 958 + pstoraster/gspcolor.h | 87 + pstoraster/gspenum.h | 40 + pstoraster/gspmdrv.h | 40 + pstoraster/gsptype1.h | 143 + pstoraster/gsptype2.h | 52 + pstoraster/gsrect.h | 61 + pstoraster/gsrefct.h | 148 + pstoraster/gsrop.h | 46 + pstoraster/gsropc.h | 60 + pstoraster/gsropt.h | 195 + pstoraster/gsshade.c | 451 + pstoraster/gsshade.h | 255 + pstoraster/gsstate.c | 1025 + pstoraster/gsstate.h | 81 + pstoraster/gsstruct.h | 970 + pstoraster/gstext.c | 344 + pstoraster/gstext.h | 231 + pstoraster/gstrap.c | 190 + pstoraster/gstrap.h | 81 + pstoraster/gstype1.c | 562 + pstoraster/gstype1.h | 265 + pstoraster/gstype2.c | 779 + pstoraster/gstype42.c | 481 + pstoraster/gstypes.h | 86 + pstoraster/gsuid.h | 78 + pstoraster/gsutil.c | 285 + pstoraster/gsutil.h | 67 + pstoraster/gsxfont.h | 45 + pstoraster/gx.h | 52 + pstoraster/gxacpath.c | 479 + pstoraster/gxalloc.h | 403 + pstoraster/gxalpha.h | 74 + pstoraster/gxarith.h | 84 + pstoraster/gxband.h | 70 + pstoraster/gxbcache.c | 153 + pstoraster/gxbcache.h | 130 + pstoraster/gxbitfmt.h | 195 + pstoraster/gxbitmap.h | 133 + pstoraster/gxbitops.h | 142 + pstoraster/gxccache.c | 456 + pstoraster/gxccman.c | 797 + pstoraster/gxchar.h | 190 + pstoraster/gxcht.c | 710 + pstoraster/gxcindex.h | 91 + pstoraster/gxclbits.c | 740 + pstoraster/gxcldev.h | 727 + pstoraster/gxclimag.c | 1316 + pstoraster/gxclio.h | 104 + pstoraster/gxclip.c | 582 + pstoraster/gxclip.h | 75 + pstoraster/gxclip2.c | 306 + pstoraster/gxclip2.h | 55 + pstoraster/gxclipm.c | 309 + pstoraster/gxclipm.h | 35 + pstoraster/gxclist.c | 734 + pstoraster/gxclist.h | 299 + pstoraster/gxclmem.c | 1151 + pstoraster/gxclmem.h | 155 + pstoraster/gxclpage.c | 127 + pstoraster/gxclpage.h | 63 + pstoraster/gxclpath.c | 1198 + pstoraster/gxclpath.h | 207 + pstoraster/gxclrast.c | 2333 + pstoraster/gxclread.c | 517 + pstoraster/gxclrect.c | 656 + pstoraster/gxclutil.c | 616 + pstoraster/gxclzlib.c | 76 + pstoraster/gxcmap.c | 890 + pstoraster/gxcmap.h | 101 + pstoraster/gxcolor2.h | 98 + pstoraster/gxcomp.h | 113 + pstoraster/gxcoord.h | 44 + pstoraster/gxcpath.c | 962 + pstoraster/gxcpath.h | 134 + pstoraster/gxcspace.h | 237 + pstoraster/gxctable.c | 146 + pstoraster/gxctable.h | 70 + pstoraster/gxcvalue.h | 48 + pstoraster/gxdcconv.c | 162 + pstoraster/gxdcconv.h | 43 + pstoraster/gxdcolor.c | 339 + pstoraster/gxdcolor.h | 199 + pstoraster/gxdda.h | 158 + pstoraster/gxdevcli.h | 877 + pstoraster/gxdevice.h | 453 + pstoraster/gxdevmem.h | 170 + pstoraster/gxdevrop.h | 35 + pstoraster/gxdht.h | 272 + pstoraster/gxdither.c | 502 + pstoraster/gxdither.h | 76 + pstoraster/gxfarith.h | 144 + pstoraster/gxfcache.h | 270 + pstoraster/gxfcmap.h | 101 + pstoraster/gxfill.c | 1543 + pstoraster/gxfixed.h | 248 + pstoraster/gxfmap.h | 105 + pstoraster/gxfont.h | 224 + pstoraster/gxfont0.h | 81 + pstoraster/gxfont1.h | 158 + pstoraster/gxfont42.h | 72 + pstoraster/gxfrac.h | 98 + pstoraster/gxftype.h | 57 + pstoraster/gxfunc.h | 56 + pstoraster/gxgetbit.h | 101 + pstoraster/gxhint1.c | 275 + pstoraster/gxhint2.c | 397 + pstoraster/gxhint3.c | 560 + pstoraster/gxht.c | 532 + pstoraster/gxht.h | 222 + pstoraster/gxhttile.h | 54 + pstoraster/gxhttype.h | 45 + pstoraster/gxi12bit.c | 300 + pstoraster/gxicolor.c | 307 + pstoraster/gxidata.c | 255 + pstoraster/gxifast.c | 716 + pstoraster/gxiinit.c | 921 + pstoraster/gximage.h | 283 + pstoraster/gximage3.c | 429 + pstoraster/gximage4.c | 297 + pstoraster/gximono.c | 586 + pstoraster/gxiodev.h | 190 + pstoraster/gxiparam.h | 172 + pstoraster/gxiscale.c | 256 + pstoraster/gxistate.h | 251 + pstoraster/gxline.h | 81 + pstoraster/gxlum.h | 50 + pstoraster/gxmatrix.h | 83 + pstoraster/gxmclip.c | 116 + pstoraster/gxmclip.h | 111 + pstoraster/gxobj.h | 230 + pstoraster/gxop1.h | 81 + pstoraster/gxp1fill.c | 374 + pstoraster/gxp1fill.h | 40 + pstoraster/gxpageq.h | 192 + pstoraster/gxpaint.c | 81 + pstoraster/gxpaint.h | 125 + pstoraster/gxpath.c | 829 + pstoraster/gxpath.h | 317 + pstoraster/gxpath2.c | 487 + pstoraster/gxpcache.h | 61 + pstoraster/gxpcmap.c | 666 + pstoraster/gxpcolor.h | 138 + pstoraster/gxpcopy.c | 824 + pstoraster/gxpdash.c | 189 + pstoraster/gxpflat.c | 455 + pstoraster/gxropc.h | 53 + pstoraster/gxsample.c | 211 + pstoraster/gxsample.h | 87 + pstoraster/gxshade.c | 348 + pstoraster/gxshade.h | 247 + pstoraster/gxshade1.c | 527 + pstoraster/gxshade4.c | 285 + pstoraster/gxshade4.h | 58 + pstoraster/gxshade6.c | 566 + pstoraster/gxstate.h | 86 + pstoraster/gxstroke.c | 1319 + pstoraster/gxsync.h | 81 + pstoraster/gxtext.h | 121 + pstoraster/gxtmap.h | 58 + pstoraster/gxtype1.c | 518 + pstoraster/gxtype1.h | 346 + pstoraster/gxxfont.h | 180 + pstoraster/gzacpath.h | 60 + pstoraster/gzcpath.h | 106 + pstoraster/gzht.h | 203 + pstoraster/gzline.h | 41 + pstoraster/gzpath.h | 385 + pstoraster/gzstate.h | 137 + pstoraster/ialloc.c | 314 + pstoraster/ialloc.h | 125 + pstoraster/iastate.h | 35 + pstoraster/iastruct.h | 34 + pstoraster/ibnum.c | 222 + pstoraster/ibnum.h | 71 + pstoraster/iccinit0.c | 31 + pstoraster/ichar.h | 72 + pstoraster/icharout.h | 59 + pstoraster/icie.h | 96 + pstoraster/icolor.h | 54 + pstoraster/iconfig.c | 74 + pstoraster/icontext.c | 275 + pstoraster/icontext.h | 59 + pstoraster/icsmap.h | 45 + pstoraster/icstate.h | 74 + pstoraster/idebug.c | 299 + pstoraster/idebug.h | 48 + pstoraster/idict.c | 780 + pstoraster/idict.h | 268 + pstoraster/idictdef.h | 128 + pstoraster/idparam.c | 371 + pstoraster/idparam.h | 90 + pstoraster/idstack.c | 249 + pstoraster/idstack.h | 125 + pstoraster/iestack.h | 56 + pstoraster/ifilter.h | 89 + pstoraster/ifont.h | 97 + pstoraster/ifunc.h | 58 + pstoraster/igc.c | 1316 + pstoraster/igc.h | 102 + pstoraster/igcref.c | 681 + pstoraster/igcstr.c | 393 + pstoraster/igcstr.h | 41 + pstoraster/igstate.h | 181 + pstoraster/iht.h | 37 + pstoraster/iimage.h | 46 + pstoraster/iimage2.h | 50 + pstoraster/iinit.c | 511 + pstoraster/ilevel.h | 39 + pstoraster/ilocate.c | 439 + pstoraster/imain.c | 664 + pstoraster/imain.h | 276 + pstoraster/imainarg.c | 849 + pstoraster/imainarg.h | 54 + pstoraster/imemory.h | 99 + pstoraster/iminst.h | 92 + pstoraster/iname.c | 637 + pstoraster/iname.h | 105 + pstoraster/inamedef.h | 230 + pstoraster/inames.h | 114 + pstoraster/interp.c | 1554 + pstoraster/interp.h | 95 + pstoraster/iostack.h | 45 + pstoraster/ipacked.h | 159 + pstoraster/iparam.c | 1080 + pstoraster/iparam.h | 118 + pstoraster/iparray.h | 42 + pstoraster/ireclaim.c | 163 + pstoraster/iref.h | 431 + pstoraster/isave.c | 1068 + pstoraster/isave.h | 133 + pstoraster/iscan.c | 1131 + pstoraster/iscan.h | 161 + pstoraster/iscanbin.c | 768 + pstoraster/iscannum.c | 398 + pstoraster/iscannum.h | 36 + pstoraster/isstate.h | 46 + pstoraster/istack.c | 588 + pstoraster/istack.h | 256 + pstoraster/istream.h | 43 + pstoraster/istruct.h | 98 + pstoraster/iutil.c | 676 + pstoraster/iutil.h | 121 + pstoraster/iutil2.c | 154 + pstoraster/iutil2.h | 56 + pstoraster/ivmspace.h | 111 + pstoraster/main.h | 101 + pstoraster/malloc_.h | 59 + pstoraster/math_.h | 97 + pstoraster/memory_.h | 107 + pstoraster/opcheck.h | 86 + pstoraster/opdef.h | 164 + pstoraster/oper.h | 108 + pstoraster/opextern.h | 115 + pstoraster/ostack.h | 94 + pstoraster/pipe_.h | 42 + pstoraster/pstoraster.c | 239 + pstoraster/sa85x.h | 51 + pstoraster/sbcp.c | 259 + pstoraster/sbhc.c | 291 + pstoraster/sbhc.h | 98 + pstoraster/sbtx.h | 45 + pstoraster/sbwbs.c | 535 + pstoraster/sbwbs.h | 78 + pstoraster/scanchar.h | 75 + pstoraster/scantab.c | 112 + pstoraster/scf.h | 213 + pstoraster/scfd.c | 809 + pstoraster/scfdtab.c | 942 + pstoraster/scfe.c | 536 + pstoraster/scfetab.c | 170 + pstoraster/scfparam.c | 99 + pstoraster/scfx.h | 132 + pstoraster/scommon.h | 173 + pstoraster/sdcparam.c | 630 + pstoraster/sdcparam.h | 57 + pstoraster/sdct.h | 121 + pstoraster/sdctc.c | 55 + pstoraster/sdctd.c | 303 + pstoraster/sdcte.c | 203 + pstoraster/sddparam.c | 83 + pstoraster/sdeparam.c | 328 + pstoraster/seexec.c | 192 + pstoraster/sfilter.h | 139 + pstoraster/sfilter1.c | 301 + pstoraster/sfilter2.c | 339 + pstoraster/sfxstdio.c | 269 + pstoraster/shc.c | 74 + pstoraster/shc.h | 254 + pstoraster/shcgen.c | 491 + pstoraster/shcgen.h | 60 + pstoraster/siscale.c | 498 + pstoraster/siscale.h | 148 + pstoraster/sjpeg.h | 80 + pstoraster/sjpegc.c | 305 + pstoraster/sjpegd.c | 100 + pstoraster/sjpege.c | 129 + pstoraster/sjpegerr.c | 102 + pstoraster/slzwc.c | 50 + pstoraster/slzwce.c | 167 + pstoraster/slzwd.c | 372 + pstoraster/slzwx.h | 80 + pstoraster/smtf.c | 184 + pstoraster/smtf.h | 49 + pstoraster/spcxd.c | 75 + pstoraster/spcxx.h | 35 + pstoraster/spdiff.c | 334 + pstoraster/spdiffx.h | 55 + pstoraster/spngp.c | 364 + pstoraster/spngpx.h | 61 + pstoraster/srld.c | 133 + pstoraster/srle.c | 203 + pstoraster/srlx.h | 77 + pstoraster/sstring.c | 464 + pstoraster/sstring.h | 79 + pstoraster/stat_.h | 62 + pstoraster/std.h | 261 + pstoraster/stdio_.h | 74 + pstoraster/stdpre.h | 422 + pstoraster/store.h | 250 + pstoraster/stream.c | 911 + pstoraster/stream.h | 334 + pstoraster/strimpl.h | 154 + pstoraster/string_.h | 59 + pstoraster/szlibc.c | 140 + pstoraster/szlibd.c | 115 + pstoraster/szlibe.c | 112 + pstoraster/szlibx.h | 64 + pstoraster/szlibxx.h | 73 + pstoraster/time_.h | 70 + pstoraster/vmsmath.h | 49 + pstoraster/zarith.c | 373 + pstoraster/zarray.c | 131 + pstoraster/zbseq.c | 136 + pstoraster/zcfont.c | 164 + pstoraster/zchar.c | 710 + pstoraster/zchar1.c | 763 + pstoraster/zchar2.c | 228 + pstoraster/zchar32.c | 217 + pstoraster/zchar42.c | 184 + pstoraster/zcharout.c | 241 + pstoraster/zcid.c | 102 + pstoraster/zcie.c | 731 + pstoraster/zcolor.c | 241 + pstoraster/zcolor1.c | 247 + pstoraster/zcolor2.c | 191 + pstoraster/zcontrol.c | 897 + pstoraster/zcrd.c | 438 + pstoraster/zcsdevn.c | 119 + pstoraster/zcsindex.c | 239 + pstoraster/zcspixel.c | 73 + pstoraster/zcssepr.c | 186 + pstoraster/zdevcal.c | 79 + pstoraster/zdevice.c | 445 + pstoraster/zdevice2.c | 373 + pstoraster/zdict.c | 515 + pstoraster/zdps1.c | 459 + pstoraster/zfbcp.c | 99 + pstoraster/zfcmap.c | 355 + pstoraster/zfdctd.c | 110 + pstoraster/zfdcte.c | 157 + pstoraster/zfdecode.c | 363 + pstoraster/zfile.c | 915 + pstoraster/zfileio.c | 842 + pstoraster/zfilter.c | 418 + pstoraster/zfilter2.c | 165 + pstoraster/zfilterx.c | 336 + pstoraster/zfname.c | 116 + pstoraster/zfont.c | 471 + pstoraster/zfont0.c | 346 + pstoraster/zfont1.c | 291 + pstoraster/zfont2.c | 553 + pstoraster/zfont32.c | 79 + pstoraster/zfont42.c | 189 + pstoraster/zfproc.c | 363 + pstoraster/zfreuse.c | 206 + pstoraster/zfunc.c | 237 + pstoraster/zfunc0.c | 113 + pstoraster/zfunc3.c | 136 + pstoraster/zfzlib.c | 105 + pstoraster/zgeneric.c | 528 + pstoraster/zgstate.c | 450 + pstoraster/zhsb.c | 68 + pstoraster/zht.c | 265 + pstoraster/zht1.c | 156 + pstoraster/zht2.c | 357 + pstoraster/zimage.c | 490 + pstoraster/zimage2.c | 158 + pstoraster/zimage3.c | 139 + pstoraster/ziodev.c | 475 + pstoraster/ziodev2.c | 148 + pstoraster/zmath.c | 277 + pstoraster/zmatrix.c | 358 + pstoraster/zmedia2.c | 472 + pstoraster/zmisc.c | 345 + pstoraster/zmisc1.c | 157 + pstoraster/zmisc2.c | 322 + pstoraster/zmisc3.c | 129 + pstoraster/zpacked.c | 258 + pstoraster/zpaint.c | 92 + pstoraster/zpath.c | 205 + pstoraster/zpath1.c | 279 + pstoraster/zpcolor.c | 264 + pstoraster/zrelbit.c | 342 + pstoraster/zshade.c | 599 + pstoraster/zstack.c | 295 + pstoraster/zstring.c | 172 + pstoraster/zsysvm.c | 164 + pstoraster/ztoken.c | 241 + pstoraster/ztrap.c | 72 + pstoraster/ztype.c | 510 + pstoraster/zupath.c | 673 + pstoraster/zusparam.c | 655 + pstoraster/zvmem.c | 404 + pstoraster/zvmem2.c | 153 + scheduler/Makefile | 153 + scheduler/auth.c | 1213 + scheduler/auth.h | 135 + scheduler/banners.c | 217 + scheduler/banners.h | 58 + scheduler/cert.c | 275 + scheduler/cert.h | 60 + scheduler/classes.c | 634 + scheduler/classes.h | 43 + scheduler/client.c | 2122 + scheduler/client.h | 104 + scheduler/conf.c | 1635 + scheduler/conf.h | 155 + scheduler/cups-lpd.c | 1234 + scheduler/cups-polld.c | 308 + scheduler/cups.pam | 2 + scheduler/cupsd.dsp | 173 + scheduler/cupsd.h | 181 + scheduler/devices.c | 479 + scheduler/dirsvc.c | 959 + scheduler/dirsvc.h | 96 + scheduler/filter.c | 301 + scheduler/ipp.c | 5373 ++ scheduler/job.c | 2866 + scheduler/job.h | 98 + scheduler/listen.c | 212 + scheduler/log.c | 440 + scheduler/main.c | 744 + scheduler/mime.c | 572 + scheduler/mime.h | 139 + scheduler/ppds.c | 665 + scheduler/printers.c | 1790 + scheduler/printers.h | 118 + scheduler/quotas.c | 236 + scheduler/server.c | 162 + scheduler/testmime.c | 223 + scheduler/testspeed.c | 126 + scheduler/type.c | 1090 + standards/draft-ietf-ipp-collection-04.txt | 2262 + ...-ietf-ipp-finishings-fold-trim-bale-00.txt | 585 + ...aft-ietf-ipp-implementers-guide-v11-02.txt | 5046 ++ standards/draft-ietf-ipp-indp-method-04.txt | 1768 + standards/draft-ietf-ipp-install-02.txt | 1426 + .../draft-ietf-ipp-job-printer-set-ops-03.txt | 3828 ++ standards/draft-ietf-ipp-job-prog-02.txt | 986 + .../draft-ietf-ipp-ldap-printer-schema-04.txt | 1456 + standards/draft-ietf-ipp-not-05.txt | 928 + standards/draft-ietf-ipp-not-over-snmp-04.txt | 9 + standards/draft-ietf-ipp-not-spec-06.txt | 4988 ++ standards/draft-ietf-ipp-notify-get-02.txt | 1711 + standards/draft-ietf-ipp-notify-mailto-03.txt | 1740 + standards/draft-ietf-ipp-notify-poll-02.txt | 9 + standards/draft-ietf-ipp-ops-admin-req-00.txt | 9 + standards/draft-ietf-ipp-ops-set2-02.txt | 9 + standards/draft-ietf-ipp-url-scheme-02.txt | 899 + standards/rfc1179.txt | 787 + standards/rfc1321.txt | 1179 + standards/rfc2246.txt | 4483 ++ standards/rfc2396.txt | 2243 + standards/rfc2487.txt | 451 + standards/rfc2565.txt | 2075 + standards/rfc2566.txt | 9691 +++ standards/rfc2567.txt | 2411 + standards/rfc2568.txt | 563 + standards/rfc2569.txt | 1571 + standards/rfc2595.txt | 843 + standards/rfc2616.txt | 9859 +++ standards/rfc2617.txt | 1907 + standards/rfc2639.txt | 3587 ++ standards/rfc2712.txt | 395 + standards/rfc2817.txt | 731 + standards/rfc2818.txt | 395 + standards/rfc2821.txt | 4427 ++ standards/rfc2822.txt | 2859 + standards/rfc2910.txt | 2579 + standards/rfc2911.txt | 12547 ++++ systemv/Makefile | 181 + systemv/accept.c | 310 + systemv/cancel.c | 286 + systemv/lp.c | 654 + systemv/lpadmin.c | 1805 + systemv/lpinfo.c | 450 + systemv/lpmove.c | 236 + systemv/lpoptions.c | 427 + systemv/lppasswd.c | 421 + systemv/lpstat.c | 1875 + templates/Makefile | 102 + templates/add-class.tmpl | 33 + templates/add-printer.tmpl | 33 + templates/admin-op.tmpl | 1 + templates/admin.tmpl | 57 + templates/choose-device.tmpl | 32 + templates/choose-make.tmpl | 35 + templates/choose-members.tmpl | 30 + templates/choose-model.tmpl | 35 + templates/choose-serial.tmpl | 56 + templates/choose-uri.tmpl | 41 + templates/class-added.tmpl | 2 + templates/class-confirm.tmpl | 6 + templates/class-deleted.tmpl | 1 + templates/class-modified.tmpl | 2 + templates/classes.tmpl | 51 + templates/config-printer.tmpl | 6 + templates/config-printer2.tmpl | 2 + templates/error.tmpl | 3 + templates/header.tmpl | 23 + templates/job-cancel.tmpl | 1 + templates/job-hold.tmpl | 1 + templates/job-release.tmpl | 1 + templates/job-restart.tmpl | 1 + templates/jobs.tmpl | 55 + templates/modify-class.tmpl | 34 + templates/modify-printer.tmpl | 36 + templates/option-boolean.tmpl | 7 + templates/option-header.tmpl | 8 + templates/option-pickmany.tmpl | 7 + templates/option-pickone.tmpl | 7 + templates/option-trailer.tmpl | 8 + templates/printer-accept.tmpl | 1 + templates/printer-added.tmpl | 2 + templates/printer-configured.tmpl | 2 + templates/printer-confirm.tmpl | 6 + templates/printer-deleted.tmpl | 1 + templates/printer-modified.tmpl | 2 + templates/printer-reject.tmpl | 1 + templates/printer-start.tmpl | 2 + templates/printer-stop.tmpl | 2 + templates/printers.tmpl | 57 + templates/test-page.tmpl | 2 + templates/trailer.tmpl | 7 + test/4.1-requests.test | 140 + test/4.2-cups-printer-ops.test | 214 + test/4.3-job-ops.test | 297 + test/5.1-lpadmin.sh | 64 + test/5.2-lpc.sh | 40 + test/5.3-lpq.sh | 40 + test/5.4-lpstat.sh | 40 + test/5.5-lp.sh | 52 + test/5.6-lpr.sh | 52 + test/5.7-lprm.sh | 52 + test/5.8-cancel.sh | 52 + test/5.9-lpinfo.sh | 52 + test/Makefile | 63 + test/create-job-format.test | 56 + test/create-job-sheets.test | 55 + test/create-job-timeout.test | 55 + test/create-job.test | 54 + test/get-devices.test | 21 + test/get-job-attributes.test | 27 + test/get-job-attributes2.test | 28 + test/get-ppds.test | 21 + test/get-printer-attributes.test | 43 + test/ipptest.c | 801 + test/print-job-hold.test | 33 + test/print-job.test | 32 + test/run-stp-tests.sh | 310 + test/set-attrs-hold.test | 180 + test/str-header.html | 35 + test/str-trailer.html | 5 + test/testfile.jpg | Bin 0 -> 598930 bytes test/testfile.pdf | Bin 0 -> 36613 bytes test/testfile.ps | 512 + test/testfile.txt | 60 + test/testhp.ppd | 195 + test/testps.ppd | 192 + visualc/config.h | 147 + visualc/jpeg.dsp | 284 + visualc/libpng.dsp | 149 + visualc/zlib.dsp | 141 + 1220 files changed, 577829 insertions(+) create mode 100644 CHANGES.txt create mode 100644 CREDITS.txt create mode 100644 ENCRYPTION.txt create mode 100644 INSTALL.txt create mode 100644 LICENSE.html create mode 100644 Makedefs.in create mode 100644 Makefile create mode 100644 README.txt create mode 100644 backend/Makefile create mode 100644 backend/betest.c create mode 100644 backend/ipp.c create mode 100644 backend/lpd.c create mode 100644 backend/parallel.c create mode 100644 backend/serial.c create mode 100644 backend/socket.c create mode 100644 backend/usb.c create mode 100644 berkeley/Makefile create mode 100644 berkeley/lpc.c create mode 100644 berkeley/lpq.c create mode 100644 berkeley/lpr.c create mode 100644 berkeley/lprm.c create mode 100644 cgi-bin/Makefile create mode 100644 cgi-bin/admin.c create mode 100644 cgi-bin/cgi.h create mode 100644 cgi-bin/classes.c create mode 100644 cgi-bin/html.c create mode 100644 cgi-bin/ipp-var.c create mode 100644 cgi-bin/ipp-var.h create mode 100644 cgi-bin/jobs.c create mode 100644 cgi-bin/printers.c create mode 100644 cgi-bin/template.c create mode 100644 cgi-bin/var.c create mode 100644 conf/Makefile create mode 100644 conf/classes.conf create mode 100644 conf/client.conf create mode 100644 conf/cupsd.conf create mode 100644 conf/mime.convs create mode 100644 conf/mime.types create mode 100644 conf/printcap create mode 100644 conf/printers.conf create mode 100644 config.h.in create mode 100644 configure.in create mode 100644 cups.dsw create mode 100644 cups.list create mode 100755 cups.sh.in create mode 100644 cups.spec create mode 100644 cups/Makefile create mode 100644 cups/cups.dsp create mode 100644 cups/cups.h create mode 100644 cups/cups_C.h create mode 100644 cups/debug.h create mode 100644 cups/dest.c create mode 100644 cups/emit.c create mode 100644 cups/encode.c create mode 100644 cups/http.c create mode 100644 cups/http.h create mode 100644 cups/ipp.c create mode 100644 cups/ipp.h create mode 100644 cups/language.c create mode 100644 cups/language.h create mode 100644 cups/mark.c create mode 100644 cups/md5.c create mode 100644 cups/md5.h create mode 100644 cups/md5passwd.c create mode 100644 cups/options.c create mode 100644 cups/page.c create mode 100644 cups/ppd.c create mode 100644 cups/ppd.h create mode 100644 cups/snprintf.c create mode 100644 cups/string.c create mode 100644 cups/string.h create mode 100644 cups/tempfile.c create mode 100644 cups/testhttp.c create mode 100644 cups/testmime.dsp create mode 100644 cups/testppd.c create mode 100644 cups/testppd.dsp create mode 100644 cups/usersys.c create mode 100644 cups/util.c create mode 100644 data/HPGLprolog create mode 100644 data/Makefile create mode 100644 data/classified create mode 100644 data/confidential create mode 100644 data/cups.pam create mode 100644 data/cups.suse create mode 100644 data/iso-8859-1 create mode 100644 data/iso-8859-10 create mode 100644 data/iso-8859-13 create mode 100644 data/iso-8859-14 create mode 100644 data/iso-8859-15 create mode 100644 data/iso-8859-2 create mode 100644 data/iso-8859-3 create mode 100644 data/iso-8859-4 create mode 100644 data/iso-8859-5 create mode 100644 data/iso-8859-6 create mode 100644 data/iso-8859-7 create mode 100644 data/iso-8859-8 create mode 100644 data/iso-8859-9 create mode 100644 data/psglyphs create mode 100644 data/secret create mode 100644 data/standard create mode 100644 data/testprint.ps create mode 100644 data/topsecret create mode 100644 data/unclassified create mode 100644 data/utf-8 create mode 100644 data/windows-1250 create mode 100644 data/windows-1251 create mode 100644 data/windows-1252 create mode 100644 data/windows-1253 create mode 100644 data/windows-1254 create mode 100644 data/windows-1255 create mode 100644 data/windows-1256 create mode 100644 data/windows-1257 create mode 100644 data/windows-1258 create mode 100644 data/windows-874 create mode 100644 doc/Makefile create mode 100644 doc/cmp.html create mode 100644 doc/cmp.pdf create mode 100644 doc/cmp.shtml create mode 100644 doc/cups.css create mode 100644 doc/cupsdoc.css create mode 100644 doc/documentation.html create mode 100644 doc/figures.sc create mode 100644 doc/glossary.shtml create mode 100644 doc/idd.html create mode 100644 doc/idd.pdf create mode 100644 doc/idd.shtml create mode 100644 doc/images/accept-jobs.gif create mode 100644 doc/images/add-class.gif create mode 100644 doc/images/add-printer.gif create mode 100644 doc/images/cancel-job.gif create mode 100644 doc/images/cancel-jobs.gif create mode 100644 doc/images/cancel.gif create mode 100644 doc/images/classes.gif create mode 100644 doc/images/config-printer.gif create mode 100644 doc/images/continue.gif create mode 100644 doc/images/cups-bar.gif create mode 100644 doc/images/cups-block-diagram.gif create mode 100644 doc/images/cups-large.gif create mode 100644 doc/images/cups-medium.gif create mode 100644 doc/images/cups-small.gif create mode 100644 doc/images/delete-class.gif create mode 100644 doc/images/delete-printer.gif create mode 100644 doc/images/draft.gif create mode 100644 doc/images/hold-job.gif create mode 100644 doc/images/left.gif create mode 100644 doc/images/logo.gif create mode 100644 doc/images/manage-classes.gif create mode 100644 doc/images/manage-jobs.gif create mode 100644 doc/images/manage-printers.gif create mode 100644 doc/images/modify-class.gif create mode 100644 doc/images/modify-printer.gif create mode 100644 doc/images/navbar.gif create mode 100644 doc/images/navbar.xcf.gz create mode 100644 doc/images/print-test-page.gif create mode 100644 doc/images/printer-idle.gif create mode 100644 doc/images/printer-processing.gif create mode 100644 doc/images/printer-stopped.gif create mode 100644 doc/images/reject-jobs.gif create mode 100644 doc/images/release-job.gif create mode 100644 doc/images/restart-job.gif create mode 100644 doc/images/right.gif create mode 100644 doc/images/show-active.gif create mode 100644 doc/images/show-completed.gif create mode 100644 doc/images/start-class.gif create mode 100644 doc/images/start-printer.gif create mode 100644 doc/images/stop-class.gif create mode 100644 doc/images/stop-printer.gif create mode 100644 doc/index.html create mode 100644 doc/ipp.html create mode 100644 doc/ipp.pdf create mode 100644 doc/ipp.shtml create mode 100644 doc/overview.html create mode 100644 doc/overview.pdf create mode 100644 doc/printing-overview.shtml create mode 100644 doc/references.shtml create mode 100644 doc/sam.html create mode 100644 doc/sam.pdf create mode 100644 doc/sam.shtml create mode 100644 doc/sdd.html create mode 100644 doc/sdd.pdf create mode 100644 doc/sdd.shtml create mode 100644 doc/spm.html create mode 100644 doc/spm.pdf create mode 100644 doc/spm.shtml create mode 100644 doc/sps.html create mode 100644 doc/sps.pdf create mode 100644 doc/sps.shtml create mode 100644 doc/ssr.html create mode 100644 doc/ssr.pdf create mode 100644 doc/ssr.shtml create mode 100644 doc/stp.html create mode 100644 doc/stp.pdf create mode 100644 doc/stp.shtml create mode 100644 doc/sum.html create mode 100644 doc/sum.pdf create mode 100644 doc/sum.shtml create mode 100644 doc/svd.html create mode 100644 doc/svd.pdf create mode 100644 doc/svd.shtml create mode 100644 doc/system-overview.shtml create mode 100644 filter/Makefile create mode 100644 filter/common.c create mode 100644 filter/common.h create mode 100644 filter/form-main.c create mode 100644 filter/form-ps.c create mode 100644 filter/form-tree.c create mode 100644 filter/form.h create mode 100644 filter/hpgl-attr.c create mode 100644 filter/hpgl-char.c create mode 100644 filter/hpgl-config.c create mode 100644 filter/hpgl-input.c create mode 100644 filter/hpgl-main.c create mode 100644 filter/hpgl-polygon.c create mode 100644 filter/hpgl-prolog.c create mode 100644 filter/hpgl-vector.c create mode 100644 filter/hpgltops.h create mode 100644 filter/image-bmp.c create mode 100644 filter/image-colorspace.c create mode 100644 filter/image-gif.c create mode 100644 filter/image-jpeg.c create mode 100644 filter/image-photocd.c create mode 100644 filter/image-pix.c create mode 100644 filter/image-png.c create mode 100644 filter/image-pnm.c create mode 100644 filter/image-sgi.c create mode 100644 filter/image-sgi.h create mode 100644 filter/image-sgilib.c create mode 100644 filter/image-sun.c create mode 100644 filter/image-tiff.c create mode 100644 filter/image-zoom.c create mode 100644 filter/image.c create mode 100644 filter/image.h create mode 100644 filter/imagetops.c create mode 100644 filter/imagetoraster.c create mode 100644 filter/pstops.c create mode 100644 filter/raster.c create mode 100644 filter/raster.h create mode 100644 filter/rastertoepson.c create mode 100644 filter/rastertohp.c create mode 100644 filter/textcommon.c create mode 100644 filter/textcommon.h create mode 100644 filter/texttops.c create mode 100644 fonts/AvantGarde-Book create mode 100644 fonts/AvantGarde-BookOblique create mode 100644 fonts/AvantGarde-Demi create mode 100644 fonts/AvantGarde-DemiOblique create mode 100644 fonts/Bookman-Demi create mode 100644 fonts/Bookman-DemiItalic create mode 100644 fonts/Bookman-Light create mode 100644 fonts/Bookman-LightItalic create mode 100644 fonts/Charter-Bold create mode 100644 fonts/Charter-BoldItalic create mode 100644 fonts/Charter-Italic create mode 100644 fonts/Charter-Roman create mode 100644 fonts/Courier create mode 100644 fonts/Courier-Bold create mode 100644 fonts/Courier-BoldOblique create mode 100644 fonts/Courier-Oblique create mode 100644 fonts/Helvetica create mode 100644 fonts/Helvetica-Bold create mode 100644 fonts/Helvetica-BoldOblique create mode 100644 fonts/Helvetica-Narrow create mode 100644 fonts/Helvetica-Narrow-Bold create mode 100644 fonts/Helvetica-Narrow-BoldOblique create mode 100644 fonts/Helvetica-Narrow-Oblique create mode 100644 fonts/Helvetica-Oblique create mode 100644 fonts/Makefile create mode 100644 fonts/NewCenturySchlbk-Bold create mode 100644 fonts/NewCenturySchlbk-BoldItalic create mode 100644 fonts/NewCenturySchlbk-Italic create mode 100644 fonts/NewCenturySchlbk-Roman create mode 100644 fonts/Palatino-Bold create mode 100644 fonts/Palatino-BoldItalic create mode 100644 fonts/Palatino-Italic create mode 100644 fonts/Palatino-Roman create mode 100644 fonts/Symbol create mode 100644 fonts/Times-Bold create mode 100644 fonts/Times-BoldItalic create mode 100644 fonts/Times-Italic create mode 100644 fonts/Times-Roman create mode 100644 fonts/Utopia-Bold create mode 100644 fonts/Utopia-BoldItalic create mode 100644 fonts/Utopia-Italic create mode 100644 fonts/Utopia-Regular create mode 100644 fonts/ZapfChancery-MediumItalic create mode 100644 fonts/ZapfDingbats create mode 100644 locale/C/cups_C create mode 100644 locale/Makefile create mode 100644 locale/de/cups_de create mode 100644 locale/en/cups_en create mode 100644 locale/es/cups_es create mode 100644 locale/fr/cups_fr create mode 100644 locale/it/cups_it create mode 100644 locale/locale.txt create mode 100644 locale/translate.c create mode 100644 man/Makefile create mode 100644 man/accept.man create mode 100644 man/backend.man create mode 100644 man/classes.conf.man create mode 100644 man/cups-lpd.man create mode 100644 man/cups-polld.man create mode 100644 man/cupsd.conf.man create mode 100644 man/cupsd.man create mode 100644 man/enable.man create mode 100644 man/filter.man create mode 100644 man/lp.man create mode 100644 man/lpadmin.man create mode 100644 man/lpc.man create mode 100644 man/lpinfo.man create mode 100644 man/lpmove.man create mode 100644 man/lpoptions.man create mode 100644 man/lpq.man create mode 100644 man/lpr.man create mode 100644 man/lprm.man create mode 100644 man/lpstat.man create mode 100644 man/mime.convs.man create mode 100644 man/mime.types.man create mode 100644 man/printers.conf.man create mode 100644 pdftops/Array.cxx create mode 100644 pdftops/Array.h create mode 100644 pdftops/CNS13CMapInfo.h create mode 100644 pdftops/COPYING create mode 100644 pdftops/Catalog.cxx create mode 100644 pdftops/Catalog.h create mode 100644 pdftops/CompactFontInfo.h create mode 100644 pdftops/Decrypt.cxx create mode 100644 pdftops/Decrypt.h create mode 100644 pdftops/Dict.cxx create mode 100644 pdftops/Dict.h create mode 100644 pdftops/Error.cxx create mode 100644 pdftops/Error.h create mode 100644 pdftops/FontEncoding.cxx create mode 100644 pdftops/FontEncoding.h create mode 100644 pdftops/FontFile.cxx create mode 100644 pdftops/FontFile.h create mode 100644 pdftops/FontInfo.h create mode 100644 pdftops/FormWidget.cxx create mode 100644 pdftops/FormWidget.h create mode 100644 pdftops/GB12CMapInfo.h create mode 100644 pdftops/GString.cxx create mode 100644 pdftops/GString.h create mode 100644 pdftops/Gfx.cxx create mode 100644 pdftops/Gfx.h create mode 100644 pdftops/GfxFont.cxx create mode 100644 pdftops/GfxFont.h create mode 100644 pdftops/GfxState.cxx create mode 100644 pdftops/GfxState.h create mode 100644 pdftops/Japan12CMapInfo.h create mode 100644 pdftops/Japan12ToRKSJ.h create mode 100644 pdftops/Lexer.cxx create mode 100644 pdftops/Lexer.h create mode 100644 pdftops/Link.cxx create mode 100644 pdftops/Link.h create mode 100644 pdftops/Makefile create mode 100644 pdftops/Object.cxx create mode 100644 pdftops/Object.h create mode 100644 pdftops/OutputDev.cxx create mode 100644 pdftops/OutputDev.h create mode 100644 pdftops/PDFDoc.cxx create mode 100644 pdftops/PDFDoc.h create mode 100644 pdftops/PSOutputDev.cxx create mode 100644 pdftops/PSOutputDev.h create mode 100644 pdftops/Page.cxx create mode 100644 pdftops/Page.h create mode 100644 pdftops/Params.cxx create mode 100644 pdftops/Params.h create mode 100644 pdftops/Parser.cxx create mode 100644 pdftops/Parser.h create mode 100644 pdftops/README create mode 100644 pdftops/SFont.h create mode 100644 pdftops/StdFontInfo.h create mode 100644 pdftops/Stream-CCITT.h create mode 100644 pdftops/Stream.cxx create mode 100644 pdftops/Stream.h create mode 100644 pdftops/T1Font.h create mode 100644 pdftops/TTFont.h create mode 100644 pdftops/XRef.cxx create mode 100644 pdftops/XRef.h create mode 100644 pdftops/config.h create mode 100644 pdftops/configure.in create mode 100644 pdftops/gfile.cxx create mode 100644 pdftops/gfile.h create mode 100644 pdftops/gmem.c create mode 100644 pdftops/gmem.h create mode 100644 pdftops/gmempp.cxx create mode 100644 pdftops/gtypes.h create mode 100644 pdftops/parseargs.c create mode 100644 pdftops/parseargs.h create mode 100644 pdftops/pdftops.cxx create mode 100644 ppd/Makefile create mode 100644 ppd/deskjet.ppd create mode 100644 ppd/deskjet2.ppd create mode 100644 ppd/epson24.ppd create mode 100644 ppd/epson9.ppd create mode 100644 ppd/laserjet.ppd create mode 100644 ppd/okidat24.ppd create mode 100644 ppd/okidata9.ppd create mode 100644 ppd/stcolor.ppd create mode 100644 ppd/stphoto.ppd create mode 100644 pstoraster/Dependencies create mode 100644 pstoraster/Fontmap create mode 100644 pstoraster/Makefile create mode 100644 pstoraster/bfont.h create mode 100644 pstoraster/bseq.h create mode 100644 pstoraster/btoken.h create mode 100644 pstoraster/ctype_.h create mode 100644 pstoraster/dirent_.h create mode 100644 pstoraster/dstack.h create mode 100644 pstoraster/errno_.h create mode 100644 pstoraster/errors.h create mode 100644 pstoraster/estack.h create mode 100644 pstoraster/files.h create mode 100644 pstoraster/fname.h create mode 100644 pstoraster/gconf.h create mode 100644 pstoraster/gconfig.c create mode 100644 pstoraster/gconfig.h create mode 100644 pstoraster/gconfig_.h create mode 100644 pstoraster/gconfigv.h create mode 100644 pstoraster/gdebug.h create mode 100644 pstoraster/gdev8bcm.h create mode 100644 pstoraster/gdevabuf.c create mode 100644 pstoraster/gdevbbox.c create mode 100644 pstoraster/gdevbbox.h create mode 100644 pstoraster/gdevcmap.h create mode 100644 pstoraster/gdevcups.c create mode 100644 pstoraster/gdevdbit.c create mode 100644 pstoraster/gdevddrw.c create mode 100644 pstoraster/gdevdflt.c create mode 100644 pstoraster/gdevdgbr.c create mode 100644 pstoraster/gdevhit.c create mode 100644 pstoraster/gdevht.h create mode 100644 pstoraster/gdevm1.c create mode 100644 pstoraster/gdevm16.c create mode 100644 pstoraster/gdevm2.c create mode 100644 pstoraster/gdevm24.c create mode 100644 pstoraster/gdevm32.c create mode 100644 pstoraster/gdevm4.c create mode 100644 pstoraster/gdevm8.c create mode 100644 pstoraster/gdevmem.c create mode 100644 pstoraster/gdevmem.h create mode 100644 pstoraster/gdevmgr.h create mode 100644 pstoraster/gdevmpla.c create mode 100644 pstoraster/gdevmrop.h create mode 100644 pstoraster/gdevnfwd.c create mode 100644 pstoraster/gdevpccm.h create mode 100644 pstoraster/gdevpcfb.h create mode 100644 pstoraster/gdevpcl.h create mode 100644 pstoraster/gdevpipe.c create mode 100644 pstoraster/gdevpm.h create mode 100644 pstoraster/gdevprn.c create mode 100644 pstoraster/gdevprn.h create mode 100644 pstoraster/gdevprna.h create mode 100644 pstoraster/gdevps.c create mode 100644 pstoraster/gdevpsde.c create mode 100644 pstoraster/gdevpsdf.c create mode 100644 pstoraster/gdevpsdf.h create mode 100644 pstoraster/gdevpsdi.c create mode 100644 pstoraster/gdevpsdp.c create mode 100644 pstoraster/gdevpsds.c create mode 100644 pstoraster/gdevpsds.h create mode 100644 pstoraster/gdevpstr.h create mode 100644 pstoraster/gdevpxop.h create mode 100644 pstoraster/gdevvec.c create mode 100644 pstoraster/gdevvec.h create mode 100644 pstoraster/genarch.c create mode 100644 pstoraster/ghost.h create mode 100644 pstoraster/gp.h create mode 100644 pstoraster/gp_getnv.c create mode 100644 pstoraster/gp_nofb.c create mode 100644 pstoraster/gp_nsync.c create mode 100644 pstoraster/gp_unifn.c create mode 100644 pstoraster/gp_unifs.c create mode 100644 pstoraster/gp_unix.c create mode 100644 pstoraster/gpcheck.h create mode 100644 pstoraster/gpgetenv.h create mode 100644 pstoraster/gpsync.h create mode 100644 pstoraster/gs_btokn.ps create mode 100644 pstoraster/gs_ccfnt.ps create mode 100644 pstoraster/gs_cff.ps create mode 100644 pstoraster/gs_cidfn.ps create mode 100644 pstoraster/gs_cmap.ps create mode 100644 pstoraster/gs_cmdl.ps create mode 100644 pstoraster/gs_dbt_e.ps create mode 100644 pstoraster/gs_diskf.ps create mode 100644 pstoraster/gs_dpnxt.ps create mode 100644 pstoraster/gs_dps.ps create mode 100644 pstoraster/gs_dps1.ps create mode 100644 pstoraster/gs_dps2.ps create mode 100644 pstoraster/gs_epsf.ps create mode 100644 pstoraster/gs_fform.ps create mode 100644 pstoraster/gs_fonts.ps create mode 100644 pstoraster/gs_init.ps create mode 100644 pstoraster/gs_iso_e.ps create mode 100644 pstoraster/gs_kanji.ps create mode 100644 pstoraster/gs_ksb_e.ps create mode 100644 pstoraster/gs_lev2.ps create mode 100644 pstoraster/gs_ll3.ps create mode 100644 pstoraster/gs_mex_e.ps create mode 100644 pstoraster/gs_mro_e.ps create mode 100644 pstoraster/gs_pfile.ps create mode 100644 pstoraster/gs_res.ps create mode 100644 pstoraster/gs_setpd.ps create mode 100644 pstoraster/gs_statd.ps create mode 100644 pstoraster/gs_std_e.ps create mode 100644 pstoraster/gs_sym_e.ps create mode 100644 pstoraster/gs_ttf.ps create mode 100644 pstoraster/gs_typ32.ps create mode 100644 pstoraster/gs_typ42.ps create mode 100644 pstoraster/gs_type1.ps create mode 100644 pstoraster/gs_wan_e.ps create mode 100644 pstoraster/gs_wl1_e.ps create mode 100644 pstoraster/gs_wl2_e.ps create mode 100644 pstoraster/gs_wl5_e.ps create mode 100644 pstoraster/gsalloc.c create mode 100644 pstoraster/gsalloc.h create mode 100644 pstoraster/gsalpha.c create mode 100644 pstoraster/gsalpha.h create mode 100644 pstoraster/gsalphac.h create mode 100644 pstoraster/gsargs.c create mode 100644 pstoraster/gsargs.h create mode 100644 pstoraster/gsbitmap.h create mode 100644 pstoraster/gsbitops.c create mode 100644 pstoraster/gsbitops.h create mode 100644 pstoraster/gsbittab.c create mode 100644 pstoraster/gsbittab.h create mode 100644 pstoraster/gsccode.h create mode 100644 pstoraster/gsccolor.h create mode 100644 pstoraster/gscdefs.c create mode 100644 pstoraster/gscdefs.h create mode 100644 pstoraster/gscdevn.c create mode 100644 pstoraster/gschar.c create mode 100644 pstoraster/gschar.h create mode 100644 pstoraster/gschar0.c create mode 100644 pstoraster/gscie.c create mode 100644 pstoraster/gscie.h create mode 100644 pstoraster/gsclipsr.c create mode 100644 pstoraster/gsclipsr.h create mode 100644 pstoraster/gscolor.c create mode 100644 pstoraster/gscolor.h create mode 100644 pstoraster/gscolor1.c create mode 100644 pstoraster/gscolor1.h create mode 100644 pstoraster/gscolor2.c create mode 100644 pstoraster/gscolor2.h create mode 100644 pstoraster/gscolor3.c create mode 100644 pstoraster/gscolor3.h create mode 100644 pstoraster/gscompt.h create mode 100644 pstoraster/gscoord.c create mode 100644 pstoraster/gscoord.h create mode 100644 pstoraster/gscparam.c create mode 100644 pstoraster/gscpixel.c create mode 100644 pstoraster/gscpixel.h create mode 100644 pstoraster/gscpm.h create mode 100644 pstoraster/gscrd.c create mode 100644 pstoraster/gscrd.h create mode 100644 pstoraster/gscrdp.c create mode 100644 pstoraster/gscrdp.h create mode 100644 pstoraster/gscrypt1.h create mode 100644 pstoraster/gscscie.c create mode 100644 pstoraster/gscsel.h create mode 100644 pstoraster/gscsepnm.h create mode 100644 pstoraster/gscsepr.c create mode 100644 pstoraster/gscsepr.h create mode 100644 pstoraster/gscspace.c create mode 100644 pstoraster/gscspace.h create mode 100644 pstoraster/gsdcolor.h create mode 100644 pstoraster/gsdevice.c create mode 100644 pstoraster/gsdevice.h create mode 100644 pstoraster/gsdevmem.c create mode 100644 pstoraster/gsdll.h create mode 100644 pstoraster/gsdparam.c create mode 100644 pstoraster/gsdpnext.h create mode 100644 pstoraster/gsdps.h create mode 100644 pstoraster/gsdps1.c create mode 100644 pstoraster/gsdsrc.c create mode 100644 pstoraster/gsdsrc.h create mode 100644 pstoraster/gserror.h create mode 100644 pstoraster/gserrors.h create mode 100644 pstoraster/gsexit.h create mode 100644 pstoraster/gsfcmap.c create mode 100644 pstoraster/gsfcmap.h create mode 100644 pstoraster/gsflip.h create mode 100644 pstoraster/gsfont.c create mode 100644 pstoraster/gsfont.h create mode 100644 pstoraster/gsfont0.c create mode 100644 pstoraster/gsfunc.c create mode 100644 pstoraster/gsfunc.h create mode 100644 pstoraster/gsfunc0.c create mode 100644 pstoraster/gsfunc0.h create mode 100644 pstoraster/gsfunc3.c create mode 100644 pstoraster/gsfunc3.h create mode 100644 pstoraster/gsgc.h create mode 100644 pstoraster/gshsb.c create mode 100644 pstoraster/gshsb.h create mode 100644 pstoraster/gsht.c create mode 100644 pstoraster/gsht.h create mode 100644 pstoraster/gsht1.c create mode 100644 pstoraster/gsht1.h create mode 100644 pstoraster/gshtscr.c create mode 100644 pstoraster/gshtx.h create mode 100644 pstoraster/gsimage.c create mode 100644 pstoraster/gsimage.h create mode 100644 pstoraster/gsimpath.c create mode 100644 pstoraster/gsinit.c create mode 100644 pstoraster/gsio.h create mode 100644 pstoraster/gsiodev.c create mode 100644 pstoraster/gsiparam.h create mode 100644 pstoraster/gsiparm2.h create mode 100644 pstoraster/gsiparm3.h create mode 100644 pstoraster/gsiparm4.h create mode 100644 pstoraster/gsjconf.h create mode 100644 pstoraster/gsjmorec.h create mode 100644 pstoraster/gslib.h create mode 100644 pstoraster/gsline.c create mode 100644 pstoraster/gsline.h create mode 100644 pstoraster/gslparam.h create mode 100644 pstoraster/gsmalloc.c create mode 100644 pstoraster/gsmalloc.h create mode 100644 pstoraster/gsmatrix.c create mode 100644 pstoraster/gsmatrix.h create mode 100644 pstoraster/gsmdebug.h create mode 100644 pstoraster/gsmemlok.h create mode 100644 pstoraster/gsmemory.c create mode 100644 pstoraster/gsmemory.h create mode 100644 pstoraster/gsmemraw.h create mode 100644 pstoraster/gsmisc.c create mode 100644 pstoraster/gsnorop.c create mode 100644 pstoraster/gspaint.c create mode 100644 pstoraster/gspaint.h create mode 100644 pstoraster/gsparam.c create mode 100644 pstoraster/gsparam.h create mode 100644 pstoraster/gsparams.c create mode 100644 pstoraster/gsparams.h create mode 100644 pstoraster/gspath.c create mode 100644 pstoraster/gspath.h create mode 100644 pstoraster/gspath1.c create mode 100644 pstoraster/gspath2.h create mode 100644 pstoraster/gspcolor.c create mode 100644 pstoraster/gspcolor.h create mode 100644 pstoraster/gspenum.h create mode 100644 pstoraster/gspmdrv.h create mode 100644 pstoraster/gsptype1.h create mode 100644 pstoraster/gsptype2.h create mode 100644 pstoraster/gsrect.h create mode 100644 pstoraster/gsrefct.h create mode 100644 pstoraster/gsrop.h create mode 100644 pstoraster/gsropc.h create mode 100644 pstoraster/gsropt.h create mode 100644 pstoraster/gsshade.c create mode 100644 pstoraster/gsshade.h create mode 100644 pstoraster/gsstate.c create mode 100644 pstoraster/gsstate.h create mode 100644 pstoraster/gsstruct.h create mode 100644 pstoraster/gstext.c create mode 100644 pstoraster/gstext.h create mode 100644 pstoraster/gstrap.c create mode 100644 pstoraster/gstrap.h create mode 100644 pstoraster/gstype1.c create mode 100644 pstoraster/gstype1.h create mode 100644 pstoraster/gstype2.c create mode 100644 pstoraster/gstype42.c create mode 100644 pstoraster/gstypes.h create mode 100644 pstoraster/gsuid.h create mode 100644 pstoraster/gsutil.c create mode 100644 pstoraster/gsutil.h create mode 100644 pstoraster/gsxfont.h create mode 100644 pstoraster/gx.h create mode 100644 pstoraster/gxacpath.c create mode 100644 pstoraster/gxalloc.h create mode 100644 pstoraster/gxalpha.h create mode 100644 pstoraster/gxarith.h create mode 100644 pstoraster/gxband.h create mode 100644 pstoraster/gxbcache.c create mode 100644 pstoraster/gxbcache.h create mode 100644 pstoraster/gxbitfmt.h create mode 100644 pstoraster/gxbitmap.h create mode 100644 pstoraster/gxbitops.h create mode 100644 pstoraster/gxccache.c create mode 100644 pstoraster/gxccman.c create mode 100644 pstoraster/gxchar.h create mode 100644 pstoraster/gxcht.c create mode 100644 pstoraster/gxcindex.h create mode 100644 pstoraster/gxclbits.c create mode 100644 pstoraster/gxcldev.h create mode 100644 pstoraster/gxclimag.c create mode 100644 pstoraster/gxclio.h create mode 100644 pstoraster/gxclip.c create mode 100644 pstoraster/gxclip.h create mode 100644 pstoraster/gxclip2.c create mode 100644 pstoraster/gxclip2.h create mode 100644 pstoraster/gxclipm.c create mode 100644 pstoraster/gxclipm.h create mode 100644 pstoraster/gxclist.c create mode 100644 pstoraster/gxclist.h create mode 100644 pstoraster/gxclmem.c create mode 100644 pstoraster/gxclmem.h create mode 100644 pstoraster/gxclpage.c create mode 100644 pstoraster/gxclpage.h create mode 100644 pstoraster/gxclpath.c create mode 100644 pstoraster/gxclpath.h create mode 100644 pstoraster/gxclrast.c create mode 100644 pstoraster/gxclread.c create mode 100644 pstoraster/gxclrect.c create mode 100644 pstoraster/gxclutil.c create mode 100644 pstoraster/gxclzlib.c create mode 100644 pstoraster/gxcmap.c create mode 100644 pstoraster/gxcmap.h create mode 100644 pstoraster/gxcolor2.h create mode 100644 pstoraster/gxcomp.h create mode 100644 pstoraster/gxcoord.h create mode 100644 pstoraster/gxcpath.c create mode 100644 pstoraster/gxcpath.h create mode 100644 pstoraster/gxcspace.h create mode 100644 pstoraster/gxctable.c create mode 100644 pstoraster/gxctable.h create mode 100644 pstoraster/gxcvalue.h create mode 100644 pstoraster/gxdcconv.c create mode 100644 pstoraster/gxdcconv.h create mode 100644 pstoraster/gxdcolor.c create mode 100644 pstoraster/gxdcolor.h create mode 100644 pstoraster/gxdda.h create mode 100644 pstoraster/gxdevcli.h create mode 100644 pstoraster/gxdevice.h create mode 100644 pstoraster/gxdevmem.h create mode 100644 pstoraster/gxdevrop.h create mode 100644 pstoraster/gxdht.h create mode 100644 pstoraster/gxdither.c create mode 100644 pstoraster/gxdither.h create mode 100644 pstoraster/gxfarith.h create mode 100644 pstoraster/gxfcache.h create mode 100644 pstoraster/gxfcmap.h create mode 100644 pstoraster/gxfill.c create mode 100644 pstoraster/gxfixed.h create mode 100644 pstoraster/gxfmap.h create mode 100644 pstoraster/gxfont.h create mode 100644 pstoraster/gxfont0.h create mode 100644 pstoraster/gxfont1.h create mode 100644 pstoraster/gxfont42.h create mode 100644 pstoraster/gxfrac.h create mode 100644 pstoraster/gxftype.h create mode 100644 pstoraster/gxfunc.h create mode 100644 pstoraster/gxgetbit.h create mode 100644 pstoraster/gxhint1.c create mode 100644 pstoraster/gxhint2.c create mode 100644 pstoraster/gxhint3.c create mode 100644 pstoraster/gxht.c create mode 100644 pstoraster/gxht.h create mode 100644 pstoraster/gxhttile.h create mode 100644 pstoraster/gxhttype.h create mode 100644 pstoraster/gxi12bit.c create mode 100644 pstoraster/gxicolor.c create mode 100644 pstoraster/gxidata.c create mode 100644 pstoraster/gxifast.c create mode 100644 pstoraster/gxiinit.c create mode 100644 pstoraster/gximage.h create mode 100644 pstoraster/gximage3.c create mode 100644 pstoraster/gximage4.c create mode 100644 pstoraster/gximono.c create mode 100644 pstoraster/gxiodev.h create mode 100644 pstoraster/gxiparam.h create mode 100644 pstoraster/gxiscale.c create mode 100644 pstoraster/gxistate.h create mode 100644 pstoraster/gxline.h create mode 100644 pstoraster/gxlum.h create mode 100644 pstoraster/gxmatrix.h create mode 100644 pstoraster/gxmclip.c create mode 100644 pstoraster/gxmclip.h create mode 100644 pstoraster/gxobj.h create mode 100644 pstoraster/gxop1.h create mode 100644 pstoraster/gxp1fill.c create mode 100644 pstoraster/gxp1fill.h create mode 100644 pstoraster/gxpageq.h create mode 100644 pstoraster/gxpaint.c create mode 100644 pstoraster/gxpaint.h create mode 100644 pstoraster/gxpath.c create mode 100644 pstoraster/gxpath.h create mode 100644 pstoraster/gxpath2.c create mode 100644 pstoraster/gxpcache.h create mode 100644 pstoraster/gxpcmap.c create mode 100644 pstoraster/gxpcolor.h create mode 100644 pstoraster/gxpcopy.c create mode 100644 pstoraster/gxpdash.c create mode 100644 pstoraster/gxpflat.c create mode 100644 pstoraster/gxropc.h create mode 100644 pstoraster/gxsample.c create mode 100644 pstoraster/gxsample.h create mode 100644 pstoraster/gxshade.c create mode 100644 pstoraster/gxshade.h create mode 100644 pstoraster/gxshade1.c create mode 100644 pstoraster/gxshade4.c create mode 100644 pstoraster/gxshade4.h create mode 100644 pstoraster/gxshade6.c create mode 100644 pstoraster/gxstate.h create mode 100644 pstoraster/gxstroke.c create mode 100644 pstoraster/gxsync.h create mode 100644 pstoraster/gxtext.h create mode 100644 pstoraster/gxtmap.h create mode 100644 pstoraster/gxtype1.c create mode 100644 pstoraster/gxtype1.h create mode 100644 pstoraster/gxxfont.h create mode 100644 pstoraster/gzacpath.h create mode 100644 pstoraster/gzcpath.h create mode 100644 pstoraster/gzht.h create mode 100644 pstoraster/gzline.h create mode 100644 pstoraster/gzpath.h create mode 100644 pstoraster/gzstate.h create mode 100644 pstoraster/ialloc.c create mode 100644 pstoraster/ialloc.h create mode 100644 pstoraster/iastate.h create mode 100644 pstoraster/iastruct.h create mode 100644 pstoraster/ibnum.c create mode 100644 pstoraster/ibnum.h create mode 100644 pstoraster/iccinit0.c create mode 100644 pstoraster/ichar.h create mode 100644 pstoraster/icharout.h create mode 100644 pstoraster/icie.h create mode 100644 pstoraster/icolor.h create mode 100644 pstoraster/iconfig.c create mode 100644 pstoraster/icontext.c create mode 100644 pstoraster/icontext.h create mode 100644 pstoraster/icsmap.h create mode 100644 pstoraster/icstate.h create mode 100644 pstoraster/idebug.c create mode 100644 pstoraster/idebug.h create mode 100644 pstoraster/idict.c create mode 100644 pstoraster/idict.h create mode 100644 pstoraster/idictdef.h create mode 100644 pstoraster/idparam.c create mode 100644 pstoraster/idparam.h create mode 100644 pstoraster/idstack.c create mode 100644 pstoraster/idstack.h create mode 100644 pstoraster/iestack.h create mode 100644 pstoraster/ifilter.h create mode 100644 pstoraster/ifont.h create mode 100644 pstoraster/ifunc.h create mode 100644 pstoraster/igc.c create mode 100644 pstoraster/igc.h create mode 100644 pstoraster/igcref.c create mode 100644 pstoraster/igcstr.c create mode 100644 pstoraster/igcstr.h create mode 100644 pstoraster/igstate.h create mode 100644 pstoraster/iht.h create mode 100644 pstoraster/iimage.h create mode 100644 pstoraster/iimage2.h create mode 100644 pstoraster/iinit.c create mode 100644 pstoraster/ilevel.h create mode 100644 pstoraster/ilocate.c create mode 100644 pstoraster/imain.c create mode 100644 pstoraster/imain.h create mode 100644 pstoraster/imainarg.c create mode 100644 pstoraster/imainarg.h create mode 100644 pstoraster/imemory.h create mode 100644 pstoraster/iminst.h create mode 100644 pstoraster/iname.c create mode 100644 pstoraster/iname.h create mode 100644 pstoraster/inamedef.h create mode 100644 pstoraster/inames.h create mode 100644 pstoraster/interp.c create mode 100644 pstoraster/interp.h create mode 100644 pstoraster/iostack.h create mode 100644 pstoraster/ipacked.h create mode 100644 pstoraster/iparam.c create mode 100644 pstoraster/iparam.h create mode 100644 pstoraster/iparray.h create mode 100644 pstoraster/ireclaim.c create mode 100644 pstoraster/iref.h create mode 100644 pstoraster/isave.c create mode 100644 pstoraster/isave.h create mode 100644 pstoraster/iscan.c create mode 100644 pstoraster/iscan.h create mode 100644 pstoraster/iscanbin.c create mode 100644 pstoraster/iscannum.c create mode 100644 pstoraster/iscannum.h create mode 100644 pstoraster/isstate.h create mode 100644 pstoraster/istack.c create mode 100644 pstoraster/istack.h create mode 100644 pstoraster/istream.h create mode 100644 pstoraster/istruct.h create mode 100644 pstoraster/iutil.c create mode 100644 pstoraster/iutil.h create mode 100644 pstoraster/iutil2.c create mode 100644 pstoraster/iutil2.h create mode 100644 pstoraster/ivmspace.h create mode 100644 pstoraster/main.h create mode 100644 pstoraster/malloc_.h create mode 100644 pstoraster/math_.h create mode 100644 pstoraster/memory_.h create mode 100644 pstoraster/opcheck.h create mode 100644 pstoraster/opdef.h create mode 100644 pstoraster/oper.h create mode 100644 pstoraster/opextern.h create mode 100644 pstoraster/ostack.h create mode 100644 pstoraster/pipe_.h create mode 100644 pstoraster/pstoraster.c create mode 100644 pstoraster/sa85x.h create mode 100644 pstoraster/sbcp.c create mode 100644 pstoraster/sbhc.c create mode 100644 pstoraster/sbhc.h create mode 100644 pstoraster/sbtx.h create mode 100644 pstoraster/sbwbs.c create mode 100644 pstoraster/sbwbs.h create mode 100644 pstoraster/scanchar.h create mode 100644 pstoraster/scantab.c create mode 100644 pstoraster/scf.h create mode 100644 pstoraster/scfd.c create mode 100644 pstoraster/scfdtab.c create mode 100644 pstoraster/scfe.c create mode 100644 pstoraster/scfetab.c create mode 100644 pstoraster/scfparam.c create mode 100644 pstoraster/scfx.h create mode 100644 pstoraster/scommon.h create mode 100644 pstoraster/sdcparam.c create mode 100644 pstoraster/sdcparam.h create mode 100644 pstoraster/sdct.h create mode 100644 pstoraster/sdctc.c create mode 100644 pstoraster/sdctd.c create mode 100644 pstoraster/sdcte.c create mode 100644 pstoraster/sddparam.c create mode 100644 pstoraster/sdeparam.c create mode 100644 pstoraster/seexec.c create mode 100644 pstoraster/sfilter.h create mode 100644 pstoraster/sfilter1.c create mode 100644 pstoraster/sfilter2.c create mode 100644 pstoraster/sfxstdio.c create mode 100644 pstoraster/shc.c create mode 100644 pstoraster/shc.h create mode 100644 pstoraster/shcgen.c create mode 100644 pstoraster/shcgen.h create mode 100644 pstoraster/siscale.c create mode 100644 pstoraster/siscale.h create mode 100644 pstoraster/sjpeg.h create mode 100644 pstoraster/sjpegc.c create mode 100644 pstoraster/sjpegd.c create mode 100644 pstoraster/sjpege.c create mode 100644 pstoraster/sjpegerr.c create mode 100644 pstoraster/slzwc.c create mode 100644 pstoraster/slzwce.c create mode 100644 pstoraster/slzwd.c create mode 100644 pstoraster/slzwx.h create mode 100644 pstoraster/smtf.c create mode 100644 pstoraster/smtf.h create mode 100644 pstoraster/spcxd.c create mode 100644 pstoraster/spcxx.h create mode 100644 pstoraster/spdiff.c create mode 100644 pstoraster/spdiffx.h create mode 100644 pstoraster/spngp.c create mode 100644 pstoraster/spngpx.h create mode 100644 pstoraster/srld.c create mode 100644 pstoraster/srle.c create mode 100644 pstoraster/srlx.h create mode 100644 pstoraster/sstring.c create mode 100644 pstoraster/sstring.h create mode 100644 pstoraster/stat_.h create mode 100644 pstoraster/std.h create mode 100644 pstoraster/stdio_.h create mode 100644 pstoraster/stdpre.h create mode 100644 pstoraster/store.h create mode 100644 pstoraster/stream.c create mode 100644 pstoraster/stream.h create mode 100644 pstoraster/strimpl.h create mode 100644 pstoraster/string_.h create mode 100644 pstoraster/szlibc.c create mode 100644 pstoraster/szlibd.c create mode 100644 pstoraster/szlibe.c create mode 100644 pstoraster/szlibx.h create mode 100644 pstoraster/szlibxx.h create mode 100644 pstoraster/time_.h create mode 100644 pstoraster/vmsmath.h create mode 100644 pstoraster/zarith.c create mode 100644 pstoraster/zarray.c create mode 100644 pstoraster/zbseq.c create mode 100644 pstoraster/zcfont.c create mode 100644 pstoraster/zchar.c create mode 100644 pstoraster/zchar1.c create mode 100644 pstoraster/zchar2.c create mode 100644 pstoraster/zchar32.c create mode 100644 pstoraster/zchar42.c create mode 100644 pstoraster/zcharout.c create mode 100644 pstoraster/zcid.c create mode 100644 pstoraster/zcie.c create mode 100644 pstoraster/zcolor.c create mode 100644 pstoraster/zcolor1.c create mode 100644 pstoraster/zcolor2.c create mode 100644 pstoraster/zcontrol.c create mode 100644 pstoraster/zcrd.c create mode 100644 pstoraster/zcsdevn.c create mode 100644 pstoraster/zcsindex.c create mode 100644 pstoraster/zcspixel.c create mode 100644 pstoraster/zcssepr.c create mode 100644 pstoraster/zdevcal.c create mode 100644 pstoraster/zdevice.c create mode 100644 pstoraster/zdevice2.c create mode 100644 pstoraster/zdict.c create mode 100644 pstoraster/zdps1.c create mode 100644 pstoraster/zfbcp.c create mode 100644 pstoraster/zfcmap.c create mode 100644 pstoraster/zfdctd.c create mode 100644 pstoraster/zfdcte.c create mode 100644 pstoraster/zfdecode.c create mode 100644 pstoraster/zfile.c create mode 100644 pstoraster/zfileio.c create mode 100644 pstoraster/zfilter.c create mode 100644 pstoraster/zfilter2.c create mode 100644 pstoraster/zfilterx.c create mode 100644 pstoraster/zfname.c create mode 100644 pstoraster/zfont.c create mode 100644 pstoraster/zfont0.c create mode 100644 pstoraster/zfont1.c create mode 100644 pstoraster/zfont2.c create mode 100644 pstoraster/zfont32.c create mode 100644 pstoraster/zfont42.c create mode 100644 pstoraster/zfproc.c create mode 100644 pstoraster/zfreuse.c create mode 100644 pstoraster/zfunc.c create mode 100644 pstoraster/zfunc0.c create mode 100644 pstoraster/zfunc3.c create mode 100644 pstoraster/zfzlib.c create mode 100644 pstoraster/zgeneric.c create mode 100644 pstoraster/zgstate.c create mode 100644 pstoraster/zhsb.c create mode 100644 pstoraster/zht.c create mode 100644 pstoraster/zht1.c create mode 100644 pstoraster/zht2.c create mode 100644 pstoraster/zimage.c create mode 100644 pstoraster/zimage2.c create mode 100644 pstoraster/zimage3.c create mode 100644 pstoraster/ziodev.c create mode 100644 pstoraster/ziodev2.c create mode 100644 pstoraster/zmath.c create mode 100644 pstoraster/zmatrix.c create mode 100644 pstoraster/zmedia2.c create mode 100644 pstoraster/zmisc.c create mode 100644 pstoraster/zmisc1.c create mode 100644 pstoraster/zmisc2.c create mode 100644 pstoraster/zmisc3.c create mode 100644 pstoraster/zpacked.c create mode 100644 pstoraster/zpaint.c create mode 100644 pstoraster/zpath.c create mode 100644 pstoraster/zpath1.c create mode 100644 pstoraster/zpcolor.c create mode 100644 pstoraster/zrelbit.c create mode 100644 pstoraster/zshade.c create mode 100644 pstoraster/zstack.c create mode 100644 pstoraster/zstring.c create mode 100644 pstoraster/zsysvm.c create mode 100644 pstoraster/ztoken.c create mode 100644 pstoraster/ztrap.c create mode 100644 pstoraster/ztype.c create mode 100644 pstoraster/zupath.c create mode 100644 pstoraster/zusparam.c create mode 100644 pstoraster/zvmem.c create mode 100644 pstoraster/zvmem2.c create mode 100644 scheduler/Makefile create mode 100644 scheduler/auth.c create mode 100644 scheduler/auth.h create mode 100644 scheduler/banners.c create mode 100644 scheduler/banners.h create mode 100644 scheduler/cert.c create mode 100644 scheduler/cert.h create mode 100644 scheduler/classes.c create mode 100644 scheduler/classes.h create mode 100644 scheduler/client.c create mode 100644 scheduler/client.h create mode 100644 scheduler/conf.c create mode 100644 scheduler/conf.h create mode 100644 scheduler/cups-lpd.c create mode 100644 scheduler/cups-polld.c create mode 100644 scheduler/cups.pam create mode 100644 scheduler/cupsd.dsp create mode 100644 scheduler/cupsd.h create mode 100644 scheduler/devices.c create mode 100644 scheduler/dirsvc.c create mode 100644 scheduler/dirsvc.h create mode 100644 scheduler/filter.c create mode 100644 scheduler/ipp.c create mode 100644 scheduler/job.c create mode 100644 scheduler/job.h create mode 100644 scheduler/listen.c create mode 100644 scheduler/log.c create mode 100644 scheduler/main.c create mode 100644 scheduler/mime.c create mode 100644 scheduler/mime.h create mode 100644 scheduler/ppds.c create mode 100644 scheduler/printers.c create mode 100644 scheduler/printers.h create mode 100644 scheduler/quotas.c create mode 100644 scheduler/server.c create mode 100644 scheduler/testmime.c create mode 100644 scheduler/testspeed.c create mode 100644 scheduler/type.c create mode 100644 standards/draft-ietf-ipp-collection-04.txt create mode 100644 standards/draft-ietf-ipp-finishings-fold-trim-bale-00.txt create mode 100644 standards/draft-ietf-ipp-implementers-guide-v11-02.txt create mode 100644 standards/draft-ietf-ipp-indp-method-04.txt create mode 100644 standards/draft-ietf-ipp-install-02.txt create mode 100644 standards/draft-ietf-ipp-job-printer-set-ops-03.txt create mode 100644 standards/draft-ietf-ipp-job-prog-02.txt create mode 100644 standards/draft-ietf-ipp-ldap-printer-schema-04.txt create mode 100644 standards/draft-ietf-ipp-not-05.txt create mode 100644 standards/draft-ietf-ipp-not-over-snmp-04.txt create mode 100644 standards/draft-ietf-ipp-not-spec-06.txt create mode 100644 standards/draft-ietf-ipp-notify-get-02.txt create mode 100644 standards/draft-ietf-ipp-notify-mailto-03.txt create mode 100644 standards/draft-ietf-ipp-notify-poll-02.txt create mode 100644 standards/draft-ietf-ipp-ops-admin-req-00.txt create mode 100644 standards/draft-ietf-ipp-ops-set2-02.txt create mode 100644 standards/draft-ietf-ipp-url-scheme-02.txt create mode 100644 standards/rfc1179.txt create mode 100644 standards/rfc1321.txt create mode 100644 standards/rfc2246.txt create mode 100644 standards/rfc2396.txt create mode 100644 standards/rfc2487.txt create mode 100644 standards/rfc2565.txt create mode 100644 standards/rfc2566.txt create mode 100644 standards/rfc2567.txt create mode 100644 standards/rfc2568.txt create mode 100644 standards/rfc2569.txt create mode 100644 standards/rfc2595.txt create mode 100644 standards/rfc2616.txt create mode 100644 standards/rfc2617.txt create mode 100644 standards/rfc2639.txt create mode 100644 standards/rfc2712.txt create mode 100644 standards/rfc2817.txt create mode 100644 standards/rfc2818.txt create mode 100644 standards/rfc2821.txt create mode 100644 standards/rfc2822.txt create mode 100644 standards/rfc2910.txt create mode 100644 standards/rfc2911.txt create mode 100644 systemv/Makefile create mode 100644 systemv/accept.c create mode 100644 systemv/cancel.c create mode 100644 systemv/lp.c create mode 100644 systemv/lpadmin.c create mode 100644 systemv/lpinfo.c create mode 100644 systemv/lpmove.c create mode 100644 systemv/lpoptions.c create mode 100644 systemv/lppasswd.c create mode 100644 systemv/lpstat.c create mode 100644 templates/Makefile create mode 100644 templates/add-class.tmpl create mode 100644 templates/add-printer.tmpl create mode 100644 templates/admin-op.tmpl create mode 100644 templates/admin.tmpl create mode 100644 templates/choose-device.tmpl create mode 100644 templates/choose-make.tmpl create mode 100644 templates/choose-members.tmpl create mode 100644 templates/choose-model.tmpl create mode 100644 templates/choose-serial.tmpl create mode 100644 templates/choose-uri.tmpl create mode 100644 templates/class-added.tmpl create mode 100644 templates/class-confirm.tmpl create mode 100644 templates/class-deleted.tmpl create mode 100644 templates/class-modified.tmpl create mode 100644 templates/classes.tmpl create mode 100644 templates/config-printer.tmpl create mode 100644 templates/config-printer2.tmpl create mode 100644 templates/error.tmpl create mode 100644 templates/header.tmpl create mode 100644 templates/job-cancel.tmpl create mode 100644 templates/job-hold.tmpl create mode 100644 templates/job-release.tmpl create mode 100644 templates/job-restart.tmpl create mode 100644 templates/jobs.tmpl create mode 100644 templates/modify-class.tmpl create mode 100644 templates/modify-printer.tmpl create mode 100644 templates/option-boolean.tmpl create mode 100644 templates/option-header.tmpl create mode 100644 templates/option-pickmany.tmpl create mode 100644 templates/option-pickone.tmpl create mode 100644 templates/option-trailer.tmpl create mode 100644 templates/printer-accept.tmpl create mode 100644 templates/printer-added.tmpl create mode 100644 templates/printer-configured.tmpl create mode 100644 templates/printer-confirm.tmpl create mode 100644 templates/printer-deleted.tmpl create mode 100644 templates/printer-modified.tmpl create mode 100644 templates/printer-reject.tmpl create mode 100644 templates/printer-start.tmpl create mode 100644 templates/printer-stop.tmpl create mode 100644 templates/printers.tmpl create mode 100644 templates/test-page.tmpl create mode 100644 templates/trailer.tmpl create mode 100644 test/4.1-requests.test create mode 100644 test/4.2-cups-printer-ops.test create mode 100644 test/4.3-job-ops.test create mode 100755 test/5.1-lpadmin.sh create mode 100755 test/5.2-lpc.sh create mode 100755 test/5.3-lpq.sh create mode 100755 test/5.4-lpstat.sh create mode 100755 test/5.5-lp.sh create mode 100755 test/5.6-lpr.sh create mode 100755 test/5.7-lprm.sh create mode 100755 test/5.8-cancel.sh create mode 100755 test/5.9-lpinfo.sh create mode 100644 test/Makefile create mode 100644 test/create-job-format.test create mode 100644 test/create-job-sheets.test create mode 100644 test/create-job-timeout.test create mode 100644 test/create-job.test create mode 100644 test/get-devices.test create mode 100644 test/get-job-attributes.test create mode 100644 test/get-job-attributes2.test create mode 100644 test/get-ppds.test create mode 100644 test/get-printer-attributes.test create mode 100644 test/ipptest.c create mode 100644 test/print-job-hold.test create mode 100644 test/print-job.test create mode 100755 test/run-stp-tests.sh create mode 100644 test/set-attrs-hold.test create mode 100644 test/str-header.html create mode 100644 test/str-trailer.html create mode 100644 test/testfile.jpg create mode 100644 test/testfile.pdf create mode 100644 test/testfile.ps create mode 100644 test/testfile.txt create mode 100644 test/testhp.ppd create mode 100644 test/testps.ppd create mode 100644 visualc/config.h create mode 100644 visualc/jpeg.dsp create mode 100644 visualc/libpng.dsp create mode 100644 visualc/zlib.dsp diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000000..a248b2b944 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,1427 @@ +CHANGES.txt - 05/01/2001 +------------------------ + +CHANGES IN CUPS V1.1.7 + + - Configuration script changes, including new + "--with-docdir=/dir" option to relocate CUPS + documentation and web content according to your + favorite version of the FHS. + - Documentation updates for encryption, SLP, etc. + - New Software Test Plan and automated test script to + test CUPS prior to installation. + - All scheduler configuration files are now case + insensitive to match Apache. + - Added support for Apache ListenBackLog, LogFormat, + Require, UseCanonicalName, Satisfy, , + , LimitRequestSize, and Options + directives. + - Added support for all Apache log levels... + - Added support for "double" HostNameLookups. + - Added new "RunAsUser" directive to support non-root + configurations on the standard (priviledged) ports. + - Added support for non-root invocation of the lpd + backend (does no reserve a priviledged port, which + might not work with some LPD servers...) + - Added new PrintcapFormat directive to control the + output format of the printcap file (BSD or Solaris + formats are supported at present.) + - The CUPS directory service routines now handle + ECONNREFUSED errors gracefully rather than shutting + all browsing off. + - ippErrorString() now returns the recommended error + messages from the IPP/1.1 Model and Semantics + document. + - Fixed a minor IPP compliance issue with responses + to requests without the attributes-charset or + attributes-natural-language attributes. + - Sun fix: need httpFlush() call for chunked IPP + requests in cupsDoFileRequest(). + - httpConnect() now looks up "localhost" by name and + by address (127.0.0.1) for users the go to the + trouble of removing the required localhost entry + in /etc/hosts or on their DNS server... + - Added support for Linux 2.4.x devfs parallel port + filenames (/dev/parallel/N). + - cupsDo[File]Request() and cupsGetPPD() no longer + block trying to reconnect to a crashed or inaccessable + server. + - Added new ppdEmitJCL() function to better handle + PJL commands from PPD files. + - A bug in UpdateJob() would cause the scheduler to + consume 100% CPU until another request was submitted. + - The cancel command did not support the "-" option to + cancel all jobs on all printers. + - The cancel and lprm commands did not support cancelling + the next/current job in the queue. + - The pdftops and pstoraster filters were using unsafe + temporary file functions; while this is not a problem + in normal configurations (the CUPS temporary directory + is restricted), they now use the cupsTempFd() function. + - The mime.types file was missing the recognition rule + for Sun Raster images. + - The admin CGI was passing a printer make string to + ippSetCGIVars() that was being replaced in that + function. + - "lpoptions -l" would resave the options... + - The EPSON drivers now send the "end packet mode" + command when printing to USB devices. + - The scheduler initialized certificates before loading + the cupsd.conf file. + - The scheduler used /dev/random to collect random data, + which could block if insufficient entropy information + had been collected by the kernel. Now use + /dev/urandom. + - Fixed a bug in the whitespace skipping code in + httpGetSubField(). + - The LPD backend now supports a new "order" option: + "lpd://server/queue?order=control,data" (default) and + "lpd://server/queue?order=data,control". + - The scheduler enforced a 30 second timeout on all + clients regardless of the Timeout directive and if a + CGI was currently running. + - cupsParseOptions() now sets boolean options to + option=true or option=false. + - The "percent complete" calculations in the LPD backend + could overflow on large files, causing the percentage + to wrap to 0 every 40MB or so. + - Fixed a memory reallocation bug in pstoraster that + could cause it to crash. + - The LPD backend now sanitizes the job title to avoid + potential problems on remote LPD servers. + - The lp command did not send the requesting-user-name + attribute when altering a job. + - The pstops filter did not handle PostScript files with + lines longer than 8191 bytes. + - The scheduler no longer uses inet_addr() to convert IP + addresses in dot format (mmm.nnn.ooo.ppp) to the + 32-bit format, since it will not work for IPv6 + addresses. + - New "Classification" directive to force labeling of + the current classification on each page. + - New "page-label" attribute to add per-page labels + ("For Official Use Only", "Draft", etc.) + - The scheduler now sets the HTTPS environment variable + for CGI programs when a client connects using + encryption. + - Fixed a recursion bug in the scheduler that could + cause cupsd to crash when a printer was removed. + - The LPDEST and PRINTER environment variables didn't + support instances. + - Dropped the "file" backend from the device list that + is reported, since it is only available for *testing* + and should never be used in a production environment. + The file: device can still be used, but it won't show + up in the list of devices from lpinfo or the web + interface. + - Added support for /dev/lpa# parallel ports under *BSD. + - Added META variables to the CGI header template to + prevent caching of the results. + - Fixed an unaligned memory buffer for the pstoraster + clist states; this caused bus errors for some + combinations of printers, drivers, and options. + - Re-added black reduction for colorful colors; this + helps to prevent dark colors from getting desaturated. + (only used when converting RGB to CMYK) + - Added two new directives - MaxJobsPerPrinter and + MaxJobsPerUser - to allow an administrator to set + the maximum number of pending jobs in a queue or + submitted by a user. + - The scheduler no longer stops a printer if it can't + create the status pipe or run the filters or backend. + This will allow heavily loaded servers to service + clients or start print jobs as the load allows. + - Fixed a bug in the Set-Job-Attributes code that could + crash the scheduler (patch from Martin Zielinski) + - cupsSetDests() did not quote option values with + embedded spaces. + - Added support for the Enable-Printer and + Disable-Printer extension operations (same as + CUPS-Accept-Jobs and CUPS-Reject-Jobs.) + - The AppSocket and IPP backends now wait for the print + job to be finished before exiting; this should prevent + the loss of print jobs with older JetDirect firmware + and make consecutive print jobs print faster. + - The BMP loading code did not handle resolution values + of 0. This is a problem with BMP image files produced + by the GIMP. + - The HTTP Upgrade code (upgrade to TLS encryption) + bypassed the authentication checks. + - The HTTP Upgrade code did not send a 426 status code + to the client and end the current request. This caused + a race condition between the client and server for the + upgrade to TLS. + - Fixed a bug in the EOF and Trailer detection code in + the pstops filter. + - The imagetoraster filter did not add the margins to + the custom page size in the raster header. + - The imagetops filter did not adjust the custom page + size to the size of the printed image. + - The imagetops filter did not include DSC comments + which are required by some printers. + - The imagetops filter did not insert newlines in + Base85 encoded output, causing files to contain + lines longer than 255 characters (violation of the + DSC). + - Added support for the DeskJet 900 series duplexer + and CRET color modes in the HP driver. + - Added support for PPD-defined margins in the HP + driver. + - Fixed the debugging output from pstoraster - the + font list was not terminated by a newline. + - Some versions of the HP-UX pam_unix authentication + module apparently do not pass the appdata_ptr argument + to the conversation function, preventing the scheduler + from authenticating users using PAM under HP-UX. A + workaround using a static variable has been added to + address this problem. + - Fixed a bug in the scheduler SortPrinters() function + that could cause printers to disappear or the + scheduler to crash when adding a printer. + - Changed the pstops filter to not do per-page filtering + if the file does not conform to at least version 3.0 + of the document structuring conventions. This seems + to "fix" printing with broken apps. + - The image filters did not handle older TIFF files that + lacked the samples-per-pixel and bits-per-pixel tags. + - Added new cupsGetJobs() and cupsFreeJobs() functions + to manage print jobs. + - cupsEncodeOptions() would encode names of 0 length and + cupsAddOption() and cupsParseOptions() would add names + of 0 length. + - The scheduler might block waiting for status messages + after starting a new print job. Thanks to Florent + Guiliani for finding this bug! + + +CHANGES IN CUPS V1.1.6-3 + + - The configure script put the JPEG library before the + TIFF library; this caused problems in some + configurations since the TIFF library also supports + JPEG compression of TIFF images. + - Updated the configure script and makefiles to handle + admin man pages with the "1m" extension (HP-UX, IRIX, + Solaris, Tru64) and in odd directories (IRIX) + - The updated cupsTempFile() function did not return + the filename when called with a filename buffer of + NULL (previously it used a static buffer.) + - FreeBSD uses /dev/unlptN, but NetBSD and OpenBSD use + /dev/ulptN. + - DeletePrinter() didn't remove the printer from any + classes it was a member of. + - DeletePrinterFromClass() didn't preserve the + implicit status of a class. + - DeletePrinterFromClasses() didn't remove printers + from implicit classes. + - StartJob() didn't send the job-sheets, job-priority, + and job-hold-until attributes to remote printers. + - LoadAllJobs() was looking for job-sheets-completed + instead of job-media-sheets-completed. This would + prevent accumulation of page data after a restart + of the scheduler. + - The pstops and imagetops filters now generate copies + using the appropriate method for a Level 1, 2, or 3 + printer since some Level 2/3 printers don't support + the /#copies variable anymore. + - The man page for cups-lpd did not mention the "-o" + option. + - The IPP backend didn't handle version-not-supported + errors and revert to IPP/1.0 (previously it only checked + for a bad-request error) + - Caldera fix: lpc now reports unimplemented commands as + unimplemented, not invalid. + - Caldera fix: lpq didn't recognize BSD lpq "-a" option. + - Caldera fix: lpr didn't recognize BSD lpr "-1", "-2", + "-3", "-4", "-q", or "-U" options. + - RedHat fixes: patches to GNU Ghostscript + - SuSE fix: temp file creation patch to GNU Ghostscript + (pstoraster). + - SuSE fix: remove cgi-bin/abort.c and cgi-bin/email.c, + which are not used. + - SuSE fix: missing NULL check in cgi_initialize_post(). + - SuSE fix: potential buffer overflows in + cgi_initialize_string(). + - SuSE fix: potential buffer overflows in + ippSetCGIVars() + - SuSE fix: more NULL checks in ppdOpen(); also make + sure that all memory is freed on error to avoid memory + leaks. + - SuSE fix: Exit from child if setgid() or setuid() + fails. + - SuSE fix: Added setgroups() calls after setgid() and + setuid() calls. + - SuSE fix: potential buffer overflows in httpEncode64() + calls. + - SuSE fix: potential buffer overflows in httpSeparate() + - SuSE fix: potential buffer overflows in ippWrite() for + bad input. + - SuSE fix: potential nul skip in ppd_decode() for + missing hex digits. + + +CHANGES IN CUPS V1.1.6-2 + + - Added changes to support NetBSD startup scripts. + - Added separate compiler options for pstoraster + (Ghostscript) to avoid compiler-induced errors + from Ghostscript's twisted code. + - The mime.types file contained syntax errors. + - Updated the *BSD USB device filenames to use + the /dev/unlptN files so that the USB device + is not reset prior to printing (causes print + corruption on many printers) + - Added new cupsTempFd() function to avoid serious + security bug in glibc fopen() function. The glibc + fopen() function unlinks a file before creating it, + which opens up possible symlink attacks. + - Now reject 0-length names in add-printer and add-class + requests. + - Fix for pstoraster when ZLIB is not available. + - cupsGetPPD() didn't reconnect when a HTTP connection + was lost. + - SuSE fix: httpConnect() didn't check that the + value from gethostbyname() was a valid IPv4 address. + - SuSE fix: httpConnect() didn't allow file descriptor 0 + to be used for a socket. + - SuSE fix: ippRead() didn't confirm that all values in + a set were numeric or string types. + - SuSE fix: lppasswd race condition fixes. + - SuSE fix: directive names could overflow buffer when + reading *.conf files. + - SuSE fix: HEAD requests for PPD files did not use the + same logic as GET requests. + - SuSE fix: possible buffer overflow when adding + /index.html to requested directory name. + - SuSE fix: possible buffer overflow when converting + IPP attributes to string options for filters. + - SuSE fix: creating file: device output with mode 0666 + instead of mode 0600. + - SuSE fix: creating job info files with mode 0640 + instead of 0600. + - SuSE fix: don't rely on snprintf() for including + system name in log filenames. + - SuSE fix: add bounds checking when copying quoted + and hex strings. + + +CHANGES IN CUPS V1.1.6-1 + + - Added configure check for getting the correct + strftime() format string; %c is not Y2k safe, + and %KC and NULL are not universally supported. + + +CHANGES IN CUPS V1.1.6 + + - Fixed another possible DoS attack in httpGets() + - Added check for "LANGUAGE = PCL" and "LANGUAGE = + POSTSCRIPT" in mime.types. + - Resolution options were not being passed into the + filter programs properly. + - The default compiler options for GCC no longer include + "-g3", which apparently is deprecated in newer + versions of GCC. + - CheckJobs() could cause cupsd to crash if a job is + cancelled in StartJob(). + - The printers.conf and classes.conf files are now + written with restricted permissions. + - The round-robin algorithm used by FindAvailablePrinter() + had problems; fixes contributed by Joel Fredrikson. + - If LoadAllJobs() is unable to determine the file type + of a print job, assume "application/vnd.cups-raw". + - The web interface now provides a job_printer_name + value for any corresponding job_printer_uri value. + - The cups-lpd mini-daemon now logs the client address + and hostname as well as all commands and errors in the + syslog file. + - The IPP backend now detects the supported file formats + and only specifies the document format if it is + supported. This makes IPP printing to network print + servers and cards more reliable without affecting the + capabilities of CUPS servers. + - The time_at_xyz attributes are now converted to human- + readable dates and times for the web interfaces. + - The HP and EPSON sample drivers now correctly catch + signals and eject the current page when a job is + cancelled. + - Fixed bug in CGI code - did not ignore control + characters (e.g. newlines) in form data. This caused + sporatic web interface problems. + - The file type logging code in the scheduler referenced + the optional document-format attribute; the new code + uses the resolved MIME type instead. + - The client.conf parsing code now removes trailing + whitespace. + - The MaxJobs directive was being treated as a boolean + instead of an integer. + - The scheduler would not timeout remote printers if + BrowseInterval was set to 0. + - The lpadmin command now supports setting of options + and user-level access control. + - Added "-E" option to all printing commands to force + encryption. + - The client code did not consume the response to the + OPTIONS request when switching to secure mode. + - The scheduler did not output a Content-Length field + when responding to an OPTIONS request. + - Added documentation on using cups-lpd with xinetd + to the man page. + - The socket backend now starts retries at 5 seconds and + increases the interval to 30 seconds. This should + provide faster printing when multiple jobs/files are + queued for a printer. + - The filters and backends no longer buffer output to + stderr. This should provide much more accurate status + reporting. + + +CHANGES IN CUPS V1.1.5-2 + + - Fixed configure check for OpenSSL to work with RSA + code. + - Added configure check for , and use this + check in backend/serial.c. + - Updated configure script handling of data, + configuration, and state directories to use datadir, + sysconfdir, and localstatedir variables. + - NetBSD uses different serial port filenames than + FreeBSD and OpenBSD. + - The pdftops filter didn't need some X-specific files. + - The scheduler makefile doesn't do a chown anymore when + installing (cupsd did this automatically on startup + anyways) + + +CHANGES IN CUPS V1.1.5-1 + + - There was a typo in the top-level Makefile + - The top-level Makefile did not install an init script + for run level 5. + - The configure script did not add the "crypto" library + when checking for the OpenSSL library. + - The OKIDATA PPD files were missing. + - The config.h.in file defined the wrong version number. + - The serial backend did not define "funky_hex" under *BSD. + - Updated the Visual C++ project files and some of the + CUPS API sources to compile under Windows again. + + +CHANGES IN CUPS V1.1.5 + + - Security updates - new default configuration does + not broadcast printer information and only allows + access from the local system. + - EXPERIMENTAL encryption support - CUPS now optionally + supports TLS/SSL encryption via the OpenSSL library. + - Documentation updates. + - Makefile/configure script updates. + - The RPM spec file didn't work out-of-the-box under + RedHat or Mandrake. + - Minor code cleanup to remove extraneous compiler + warnings. + - cupsTempFile() was using %p for the temporary + filename; this should have been %08x (just 8 digit + hex) + - Deleting a printer with active print jobs would still + crash the server. + - ippWrite() and ipp_write_file() didn't send the + correct value length for name-with-language and + text-with-language attributes. + - Updated IPP code to support copied strings (that + should not be freed); this provides slightly more + efficient IPP server performance. + - Updated PDF filter to Xpdf 0.91. + - httpGets() could go into an infinite loop if a line + longer than the input buffer size was sent by a + client. This could be used in a Denial-of-Service + attack. + - The lpstat and CUPS API functions now request only the + data required when getting the list of printer or + class information. This should improve performance + with large numbers of printers on slower machines. + - The scheduler was always enforcing the FilterLimit, + even if FilterLimit was set to 0. + - Updated the Linux USB backend to support Mandrake's + /dev/usb/usblp# filenames. + - The PRINTER and LPDEST environment variables did not + override the lpoptions default printer. + - The PPD read functions incorrectly included trailing + characters (usually whitespace) after quoted string + attributes. + - The multiple-document-handling attribute handling code + did not check for the correct value for collated + copies (separate-documents-uncollated-copies). + - The EPSON driver did not work with OKIDATA printers in + EPSON emulation mode (needed change-emulation command) + - The HP-GL/2 filter did not scale the plot properly in + scale mode 2. + - Added PPD files for 9-pin and 24-pin OKIDATA printers. + - The httpSeparate() function didn't handle passwords + that started with a number. + - ippDelete() could free the character set string + multiple times in name-with-language and + text-with-language attributes. + - The scheduler would access freed memory right after + freeing it (for debug messages); these parts of the + code have been reordered to avoid this situation + which was causing sporatic errors and crashes. + - The ppdClose() function didn't free all of the strings + in the ppd_file_t structure. + - The LoadAllJobs() function in the scheduler did not + close the spool directory. + - Changed all sprintf's that use string formats to + snprintf's, even if the destination buffer is + larger than the source string(s); this protects + against buffer overflows caused outside of CUPS... + - Changed all strcpy's to strncpy's between local and + global variables, even if the destination buffer is + larger than the source string; this protects + against buffer overflows caused outside of CUPS... + - The CUPS certificate functions didn't use the + CUPS_SERVERROOT environment variable when set. + - The directory services code was copying instead of + comparing the remote printer info, resulting in + unnecessary updates of the printer attributes for + remote printers. + - Added new mime.types rules to allow automatic raw + printing of PCL and ESC/P files; PJL headers are + parsed to differentiate between PostScript and + PCL job files. This should eliminate a lot of + the reports of SAMBA printing problems due to + the missing "-oraw" or "-l" options. + - The mimeLoadType() function didn't handle the + 3-argument contains() function. + - The LoadPPDs() function in the scheduler didn't + properly set the alloc_ppds variable or handle a PPD + database containing 0 printers. + - The scheduler FindAvailablePrinter() function didn't + use the same queuing logic as the CheckJobs() + function. This caused classes to stall if a remote + printer was always busy. + - Jobs are now assigned to printers in a class + round-robin style. This should prevent the first + server in the class from bearing the brunt of the + jobs. + - The scheduler's LoadAllJobs() function didn't always + restore remote printers for queued jobs on startup. + - The serial backend didn't support the higher baud + rates with the old termios interface. It now supports + 57600 and 115200 baud. + - The serial backend now supports different types of + flow control; previously it ignored the flow=XYZ + option in the device URI. + - The serial backend now supports DTR/DSR flow control, + which is popular on dot-matrix printers (access with + "flow=dtrdsr" in the device URI) + - Added new job-originating-host-name attribute for + jobs. The new attribute provides the hostname or + IP address of the machine that submitted the job. + - The set-job-attributes code no longer allows read-only + job attributes to be changed. + - Expanded the click area for the navigation bar in the + web interface. + - Updated the lp and cancel commands to support all of + the Solaris print options (some are simply ignored + since they do not map) + - Updated the scheduler to limit the number of file + descriptors to the maximum select() set size. This + was causing problems on Solaris systems where the + max FD count was increased beyond 1024. + - The scheduler's LoadDevices() function was getting + interrupted by the SIGCHLD signal handler; now ignore + child signals while loading devices. + - Added quota and allow/deny user support for printers + and classes. + - Removed black/CMY adjustment code from the PS and + image file RIPs; it was interfering with some CUPS + driver dithering code. + - The lpc program stopped listing the queue statuses + after the first active printer. + - The cups-lpd program used an output format that the + Solaris printing system did not understand. + - Updated the lpq program to use the Solaris format + except under Tru64 UNIX. + - Some DEC PPD files incorrectly use "Off" for the null + value in UI constraints. Added "Off" to the list of + accepted null values. + - Changed the *BSD define constants to __*BSD__ in all + of the backends. + - Added support for "lpstat printername", which is an + undocumented feature in Solaris. + - The HP-GL/2 filter now only sets the plot size if it + is set in the plot file. + - The lpmove command wasn't sending the requesting + user name, causing it to always fail. + - Updated the cupsTempFile() code to use GetTempPath() + under Windows. + - The cups-lpd mini-daemon didn't limit the number of + data files accepted, didn't use cupsTempFile(), + didn't handle control file job information in any + order, and didn't free job options after printing + a file. + - The scheduler copy_banner() function did not + explicitly set the owner and permissions of the banner + files, which could prevent the banner pages from + printing on some systems. + - The lpstat program wasn't listing remote classes. + - The scheduler did not verify that the printer-uri + attribute was specified in all requests that required + it. + + +CHANGES IN CUPS v1.1.4 + + - Makefile and configure script fixes. + - **** Changed the default Printcap setting **** to + /etc/printcap. There are just too many people asking + why application XYZ doesn't see their printers! + - The web admin interface now displays an error if it + can't get the list of printer drivers from cupsd. + - The IPP backend was putting the copies option before + the other job options were set. This caused the IPP + request to contain attribute groups in the wrong + order, which prevented remote printing. + - Added checks in scheduler to free memory used for + IPP requests and language information when closing + a client connection. + - Fixed the duplex option in the HP LaserJet driver. It + should now work with all LaserJet printers (and + compatibles) + - The add-printer web interface didn't initialize the + "old info" data pointer, which caused random crashes + on many OS's. + - Fixed many page sizes defined in the Level 1 + compatibility file "gs_statd.ps" to match reality. + - Fixed another bug in the setpagedevice "code" in + Ghostscript. It should now accept all standard + Adobe attributes on all platforms. + - Fixed pstoraster so that it reallocates memory for + color depth changes as well as size/resolution + changes. This removes an ordering constraint on + the color, page size, and resolution options in + PPD files. + - The IPP backend didn't use the job's character set + when the destination printer supported it. This + caused problems when printing text files to other + CUPS servers. + - Updated the logic used to determine when to rebuild + the PPD file database. The scheduler now checks the + dates and the number of PPD files (was just checking + the dates.) + - Updated the ippSetCGIVars() function (used by the + web interfaces) to only filter valid string values. + - The PostScript filter was scaling 2-up pages + incorrectly. This caused the edges of some pages to + be clipped. + + +CHANGES IN CUPS v1.1.3 + + - Makefile fixes. + - RPM spec file changes. + - Documentation updates. + - Enabled pstoraster debug messages for everything + (only logged when LogLevel set to "debug"...) + - Changed the Input/OutputAttributes fix in + pstoraster so that it works on all platforms. + - The HP-GL/2 filter didn't set the right green + color value in encoded polylines or text. + - Updated the "fitplot" code to handle plot sizes + specified as "PSwidth,length" and "PSlength,width". + - Updated the Linux parallel and USB backends to open + the device files prior to looking in /proc for + autoprobe info. This makes sure that loadable device + driver modules are in fact loaded... + - Added new FilterLimit directive to limit the number + of processing jobs/filters on a system. + - set-job-attributes didn't change the job-state to + held/pending when the job-hold-until attribute was + specified. + - set-job-attributes didn't save the new job attributes. + - Now change the "requesting-user-name" attribute in + requests from remote systems to "remroot" when an + unauthenticated "root" user is sent. This can be + changed using the new RemoteRoot directive in + cupsd.conf. + - The cancel-job, hold-job, release-job, and restart-job + operations didn't log the authenticated username. + - The cups-lpd mini-daemon now checks for a + document-format option before forcing raw mode with + filter mode 'l'. + - The cups-lpd mini-daemon now supports "-o" options + on the command-line (passed by inetd) to set global + defaults for all print queues. + - The pstops filter assumed that a file with a Trailer + comment would also have an EOF comment. + - Added new cupsSetPasswordCB(), cupsSetServer(), + cupsSetUser(), and ippSetPort() functions to better + support client applications (especially GUIs...) + - The CUPS-add-class and CUPS-add-printer operations + didn't reset the printer-name attribute on remote + print queues that had to be renamed when a local + printer was defined with the same name. + - The lpoptions command now supports a "-r" option to + remove options for a printer or instance. + - The lpadmin and admin.cgi programs no longer allow + class and printer names to begin with a number; this + caused the command-line utilities to become confused. + - The Linux USB backend now looks for both the parallel + and usblp driver names in the device list. + - Added a new FontPath directive to cupsd.conf, and also + a "--with-fontpath" option for the configure script to + specify alternate font paths for pstoraster. + - The CUPS-move-job operation didn't update the + job-printer-uri attribute. + - The scheduler only looked up printers and classes by + name in IPP requests, instead of using the full URI. + This caused problems with KUPS and friends with + remote printers. + - The scheduler now handles better localization of + hostnames (e.g. server is host.foo.com, remote is + host.subfoo.foo.com, localized is not host.subfoo...) + - The scheduler logging functions now use a common + log file checking/rotation function (courtesy of + Crutcher Dunnavant at Red Hat) + - The scheduler could accept more client connections + than it allocated for if more than one Port or Listen + line was present in cupsd.conf. + - Other minor scheduler performance tweeks. + - The lpq and lprm commands didn't support the default + printer set using lpoptions. + - The lpoptions command now supports a "-l" option to + list the printer-specific options and their current + settings. + - The web printer and class lists now show a link to the + default printer or class at the top of the page. + - The text filter now supports pretty printing of shell + and perl scripts as well as C/C++ source files. + - The top and bottom margins were reversed for landscape + text printing. + - The lpq and lprm commands didn't understand printer + instances. + - The scheduler only selected on the first 100 file + descriptors instead of the maximum file descriptor + limit. + - The scheduler client, listener, and mainline functions + now share code to disable and enable monitoring for + new client connections. + - The imagetoraster filter didn't support all of the + required pagedevice parameters. + - The serial backend now checks for 100 serial ports + under Linux. + - The scheduler used sscanf() to pull out the remote + printer location, description, and make/model strings, + but if any of these options was empty then sscanf() + would stop processing. + - Added "debug2" log level to provide a little less + verbose debugging information at the "debug" level. + - The scheduler would crash if you stopped a printer + that was currently printing a job. + - The scheduler incorrectly allowed jobs in the cancelled, + aborted, or completed state to be cancelled. + - The image filters did not load TIFF images properly + for bottom-to-top and right-to-left orientations. + - Added new cupsEncodeOptions() function to encode + CUPS options as IPP job attributes. + - The IPP backend, LPD mini-daemon, client commands, + and CUPS API did not properly encode multiple + option values separated by commas. + - Added new scheduler malloc logging in debug mode + (provides summary of total arena size, allocated, + and free bytes once a minute) + - The EPM-based distributions didn't install the + correct symlinks for a few man pages. + - Fixed a memory leak in the scheduler - wasn't + freeing old filters when deleting or renaming + printers. + - The scheduler now queries the primary IP address + for the name of the server and maps any incoming + requests from that address to the server name. + This fixes web admin mapping problems from + server.domain.com to localhost. + - The web printer modify interface now remembers + the previous device and driver settings (except + for serial ports.) + - The job-k-octets attribute is now stored as part of + the job attributes; this preserves the information + after a job is completed when job file history is + turned off. + - Dropped option sub-group parsing code for the moment, + since many Xerox PPD files abuse this feature in PPD + files and don't follow the hierarchy rules. + - Added new wrapper code around options so that duplex + options for some HP printers don't prevent prints. + - Added support for Digital UNIX/Tru64 UNIX/OSF/1 format + for "lpstat -v" output. + - Now show the URI for remote printers instead of + /dev/null in "lpstat -v" output. + - Creating classes and adding printers to a class with + the lpadmin command didn't work. + - The banner pages and test page should now format + correctly in both portrait and landscape orientations. + - Updated banner page substitution so that { can appear + by itself without quoting. + + +CHANGES IN CUPS v1.1.2 + + - Makefile/configure fixes + - RPM spec file and EPM list file fixes + - The cupsTempFile() function now uses a different + algorithm for generating temp files and "reserves" + them to avoid possible security exploitation. + - Now use /dev/random (if available) to seed the random + number generator for certificates. + - The /var/spool/cups and /var/spool/cups/tmp directories + were incorrectly owned by root; they are now owned by + the filter user, typically "lp". + - The scheduler now resets the permissions on the spool + and temp directories as needed to match the filter + user. + - Now expose ppdCollect() as an externally callable + function. + - The image filters now support filtering from the + standard input. + - The imagetoraster filter now collects all printer + options and job patch files and applies them to the + page header as needed. + - Added format and banner options to LPD backend. + - The send-document operation didn't start a job + immediately when last-document was true. + - The set-job-attributes operation didn't correctly + replace the current job-hold-until value. + - Removed the option wrapper code from ppdEmit() and + friends since it caused problems with Ghostscript + and many PS printers. + - Was setting TZ environment variable twice for job + filters. + - Added syslog logging in cups-lpd to aide in + debugging problems. + - The HP-UX parallel port backend did not list the + available parallel ports on some systems (printf + calling problem...) + - The lp and lpr commands overrode user options if + -d/-P were specified after -o. + - The scheduler would crash with a */* filter. + - Added support for a "default" filter for unknown file + types. The example provided in the mime.types and + mime.convs file prints unknown files as if "-oraw" was + specified for the job. This functionality is disabled + by default. + - The "compatibility" mode fix for older backends did not + work for smbspool. Added a workaround for it. + - The HP-GL/2 filter didn't perform the right pen scaling + with some files and the "fitplot" option. + - New Software Performance Specification document that + describes the memory, disk, and CPU usage of all the + CUPS software. + + +CHANGES IN CUPS v1.1.1 + + - The pstoraster Makefile still referenced one of the + old PDF filter files. + - The filter Makefile used INSTALL_DATA instead of + INSTALL_LIB to install the CUPS image library. + - The administration CGI didn't work properly with + network devices. + - The BrowseACL variable was not updated after the + cupsd.conf file was loaded. + - The lpd mini-daemon didn't support printer instances. + - Now use a default umask of 077 for child processes. + - Now put temp files in /var/spool/cups/tmp for child + processes and the root user, unless TMPDIR or TempDir + is defined otherwise. + - cupsGetPPD() no longer uses easy-to-guess filenames. + - The CUPS-Delete-Class and CUPS-Delete-Printer + operations now save classes.conf file as needed. + - The lppasswd command wouldn't add a user. + - The ppdOpen() function could cause a segfault if a + 0-length PPD file was read. + - The image filters were not handling images with + different X and Y resolutions properly. + - The imagetoraster filter defaulted to RGB output + instead of black output like pstoraster. + - The pstops filter didn't handle binary data properly. + - The pstops filter didn't handle copies properly for + PS files lacking DSC comments. + - The pstops filter now appends %%EOF to the end of + documents if they don't have it. + - The cupsGetPPD() function didn't work with remote + printers lacking the @server in the name. + - The configure script didn't work right when only + --prefix was specified. + - The ppdEmit() code now wraps all printer commands so + that buggy PostScript printers will still print a file + after receiving an option that isn't available. + - Fixed the DeskJet margin bug, and disabled 600dpi + color mode until it can be fixed. + - The cupsAddDest() function didn't sort instances + correctly in all cases. + - The time-at-xyz attributes now expand to the date and + time in banner files. + + +CHANGES IN CUPS v1.1 + + - Documentation updates. + - Configuration script updates. + - Didn't map charset and language value strings to lowercase + and _ to - as required by SLP and IPP. + - ppdLoadXYZ() didn't add the list of available fonts to the + ppd_file_t structure. + - The text filter common code was freeing the PPD file data + before it was used. + - The text filter now embeds missing fonts. + - The CGI interface now maps local access to the server to + the localhost address. + - The HP-GL/2 filter didn't use the specified (or default) + color ranges, resulting in strange colors. + - The HP-GL/2 filter didn't default to no input window, which + caused unnecessary clipping of plots. + - Integrated Xpdf's pdftops filter into CUPS, which is a + lightweight and reliable replacement for Ghostscript's + PDF support. + - Removed all PDF support from Ghostscript. + - Updated HP driver to set top margin; this seems to fix + the offset problem seen on HP DeskJet printers. + - Fixed dependencies on the ZLIB and JPEG libraries in + pstoraster. + - The lpr command wasn't using the lpoptions defined by + the user. + - The lpr command would segfault if the CUPS server was + not running. + - The top-level makefile was not installing the CUPS + initialization script. It now does so if it sees there + is an init.d directory in /sbin, /etc/rc.d, or /etc. + - "lpstat -v all" didn't work. + - pstoraster would crash on some platforms doing the + setpagedevice operator. + - The web administration interface now allows you to set + the default banner pages. + - Images can now be positioned on the page using the new + "position" option. + - The AccessLog, ErrorLog, and PageLog directives now + support "%s" to insert the server name. + - Added a new BrowseShortNames directive to allow for + short remote printer names ("printer" instead of + "printer@server") when possible. + - The scheduler could crash if given an invalid PPD file + with no PageSize attributes. + - Updated the serial, parallel, and usb backends to do + multiple writes and ignore ioctl() errors as needed; + this should fix problems with serial printing on old + serial drivers and with the UltraSPARC parallel port + driver under Solaris 2.7. + - Now propagate LD_LIBRARY_PATH to child processes from + cupsd. + - New DataDir directive for installing in alternate + locations. + - New CUPS_SERVERROOT and CUPS_DATADIR environment + variables to specify installation directories as + needed. + - Queued remote jobs recreate remote printers as needed + when the scheduler is started. + - Deleting a printer also purges all jobs on that + printer. + - Old job and control files that don't belong to a + printer are automatically deleted. + - Wasn't updating time-at-processing and + time-at-completed attributes in job. + - Didn't send required multiple-operation-time-out + attribute in response to a get-printer-attributes + request. + - cups-lpd now supports options set with lpoptions. + - The job-hold-until attribute is now provided with all + jobs. For jobs that are not currently held the value + is "no-hold". + - The scheduler was not sending "unknown" values in IPP + responses. + - The lpoptions command now accumulates options from + previous runs rather than replacing all options for a + printer. + - The IPP backend now switches to IPP/1.0 if a 1.1 + request fails. + - The lpadmin and admin.cgi programs now validate new + printer and class names. + - The access_log file now includes the number of IPP bytes + received in a POST request. + + +CHANGES IN CUPS v1.1b5 + + - Documentation updates. + - The pstoraster filter didn't compile without the JPEG library. + - The cupsd server didn't support the HTTP OPTIONS request + method. + - Dropped the "CLOSE" method supported by the cupsd server. + (not defined in HTTP specification) + - Makefile/configure script fixes. + - Missing the job-restart template. + - Added IPP test suite for testing. + - Missing IPP documentation from binary distributions. + - Fixed multiple-document handling code when last-document + not specified. + - Added more checks to IPP requests to prevent bad requests + from getting through. + - Not all of the Ghostscript error output was being sent to + stderr. + - The PostScript filter now added PJL commands to set the + job name and display string, if supported. + - The scheduler would crash if the browse socket could not + be bound. Now disables browsing if port 631 (reserved for + IPP) is being used by a misbehaving daemon. + - The USB backend now looks for the older Linux 2.2.x USB + printer device filenames as well as the newer ones. + - The IPP backend now uses the UTF-8 charset exclusively, + since apparently only CUPS handles more than US-ASCII and + UTF-8... + - Wasn't quoting ( in PostScript banners... + - Send-document requests with no document-format attribute + could cause cupsd to crash. + - Old jobs in the spool directory might cause cupsd to + crash. + - CUPS now supports all of the recommended job-hold-until + keywords as well as name values of the form "HH:MM" and + "HH:MM:SS". + - Added placeholder pointer for TLS encryption to the HTTP + connection structure. + - Fixed the "fast poll" bug reported by DISA - the + status pipe wasn't being closed for multi-file jobs. + - Revamped put_params code in pstoraster to fix bitmap + allocation bug with FrameMaker output. + - Ripped out filename, etc. code from pstoraster as it + is a potential security hole. + - Added support for RIP_CACHE environment variable in the + new pstoraster. + - Fixed USB device filenames for Linux; now support new + pre-2.4 devices (/dev/usb/lp#) and 2.2 devices + (/dev/usblp#) + - Fixed accept-jobs crash with classes. + - Didn't include dot-matrix EPSON drivers in previous + release. + + +CHANGES IN CUPS v1.1b4 + + - Documentation updates. + - Many makefile and configuration script fixes (should + now compile better under *BSD.) + - The MediaPosition attribute was being mishandled by + GhostScript, causing the RIP to fail whenever a paper + tray was selected. + - The scheduler now logs the final line of log information + from a filter, even if it doesn't end with a newline; this + primarily affects GhostScript error output. + - The scheduler was saving implicit classes, so after a few + restarts you'll end up with AnyPrinter, AnyAnyPrinter, etc. + - The JPEG autodetection didn't work with some JPEG files that + came from digital cameras (JPEG but not JFIF); the new + magic types should work with all images that the JPEG library + can handle. + - Fixed a bug in the new contains() MIME type rule that could + cause cupsd to crash. + - Switched to using strtol() in the MIME type code so that you + can use hex, octal, or decimal constants as desired in the + mime.types file. + - Banner files are now treated as templates, allowing any type + of file to be used as a banner. + - Added a 30-second timeout to backend device reports so that a + hung backend will not prevent the scheduler from starting. + - Backends are once again terminated when jobs are stopped; the + CUPS-supplied backends will stay alive until the downstream + filters have had a chance to clear out old page data. + - The charset lookup in the CUPS localization support was wrong + (iso8859-x instead of iso-8859-x) + - Changed the "cpNNNN" code page files to "windows-NNNN" to match + the IANA registrations. + - New PostScript banner pages. + - Added Windows BMP and Alias PIX image file support to the image + filter. + - The PNG reading coded didn't free all of its buffers. + - Added Digest authentication support to the client and server + code. + - Added Solaris options to System V commands. + - Now support the output-bin job template attribute. + - Now log the job-billing attribute in the page_log file, and + keep track of the total number of pages in the + job-media-sheets-completed attribute. + - The penwidth option is now in micrometers to support more + accurate width specification. + - The image filters now support interlaced and transparent PNG + files. + - Didn't handle Keep-Alive for HTTP/1.0 clients. + - The BrowsePoll support didn't handle when BrowseInterval + was set to 0 (now uses 30 seconds if BrowseInterval is 0) + - The DeskJet driver now supports 600 DPI color for printers + that support it. + - New lpinfo and lpmove commands. + - The lpq command now supports the Digital UNIX output format. + - The LPD mini-daemon now supports all required LPD operations. + - Implemented timeouts for multi-file documents. + - New cupsPrintFiles() function in the CUPS API library to + print multiple files using create-job and send-document + requests (1 job ID for multiple files) + - The lp command now sends multiple files as a single job, + matching the behavior of the System V command. + - The "cancel -a" command now purges job history files. + + +CHANGES IN CUPS v1.1b3 + + - Documentation updates. + - The startup script redirected stderr before stdout, + which caused problems with some versions of Bourne + shell and Bash. + - Fixed a bug in the scheduler's PPD language reading + code. + - Fixed a bug in the scheduler's check for the + manufacturer in the PPD. + - The pstoraster filter didn't allow some input and + output attributes to be set. + - Added banner page support. + - Added missing PAM configuration file. + - Configuration script fixes for Linux and *BSD. + - The log file code was using the wrong sign for the + timezone offset. + - The default printcap file is now empty (no printcap + file is generated). + - The scheduler did not start jobs destined for remote + printers when they became available. + - The scheduler now sends jobs to remote printers + immediately. (when sending jobs to a class, the remote + printer is only used when it becomes available) + - The scheduler now supports printing of banner pages + via the job-sheets attribute (banner files go in + /usr/share/cups/banners) + - The cupsd process now forks itself into the background + (override with -f) + - Added several *BSD enhancements. + - Added UNSUPPORTED libtool option to configuration + script to allow the use of libtool. Note that this is + UNSUPPORTED by us, but added by request of the *BSD + folks. + - The parallel, serial, and usb backends now retry the + opening of their ports. This allows multiple print + queues to be associated with a single physical port, + and will allow CUPS to support several types of + parallel port auto-switches in the near future. + - Set-Job-Attributes now supports adding, changing, and + deleting job template attributes, and no longer allows + job-printer-uri to be set (see CUPS-Move-Job) + - Added CUPS-Move-Job operation to support moving of jobs. + - The CGI template functionality now supports multiple + languages (still only have templates for English) + - The CUPS-Get-Printers and CUPS-Get-Classes operations + now support filtering as defined in the IDD. + - The Get-Jobs, CUPS-Get-Printers, and CUPS-Get-Classes + operations no longer limit themselves to 1000 jobs, + printers, or classes (believe it or not, this is + needed for some sites) + - The web interfaces now support language-specific + templates. + - The web admin interface now supports class management. + - The web admin interface now shows a list of + manufacturers before selecting the PPD/driver for a + specific printer. + - The web admin interface now supports configuration of + the default printer options in the PPD file. + - The web interface now uses printer/class + authentication for the test page instead of admin + authentication. + - Updated the RPM spec file for the current release. + - Updated language support for Windows code pages. + - 8-bit character set files can now use multiple fonts + (needed for Arabic, Greek, Hebrew, etc.) + - Added basic right-to-left text support in the text + filter. + - The POSIX locale now uses ISO-8859-1 instead of + US-ASCII. + - Fixed PDF printing problems. + - Fixed PostScript RIP page device dictionary elements + that weren't getting passed in cups_get_params(). + - Added a new "contains" rule for the magic file typing. + - The "printable" rule now accepts characters from 128 to 255 + (needed for Microsoft character sets) + - Added support for ~/.cupsrc as well as /etc/cups/client.conf + so that the default server can be configured on a per-user + basis without environment variables. + - Added LPD mini-daemon to support incoming LPD jobs. + + +CHANGES IN CUPS v1.1b2 + + - Documentation updates. + - The lp command didn't always load the user-defined + destinations, preventing it from seeing the default + printer. + - Many configure script and makefile fixes. + - The Microsoft code page files were missing from the + distribution. + - Added a workaround for the HP IPP client (which is sending + an invalid printer-uri in requests) + - Fixed the encoding of text-with-language and name-with-language + to match the IPP spec. + - Added support for unknown value tags in the IPP routines + (previously they would be ignored) + - Integrated GNU GhostScript 5.50 into the pstoraster filter. + - Client hostname resolution was broken on little-endian + machines. + - Now look at client.conf file for client's default server + and printer. + - The cupsServer() function did not close the client.conf file + if it contained a ServerName directive. + - Added BrowseAllow, BrowseDeny, BrowseOrder, BrowsePoll, and + BrowseRelay directives. + - BrowseInterval 0 disables advertising of local printers, but + still receives information on remote printers. + - New browse polling daemon (for polling servers on different + networks) + - New PPD cache file for faster startup times with large numbers + of PPD files. + - The Host: field was incorrectly required for HTTP/1.0 clients. + - New set-job-attributes operation now supported. + - The mime_load_types() and mime_load_convs() functions did not + close their input files. + + +CHANGES IN CUPS v1.1b1 + + - NEW web-based administration interface. + - NEW EPSON printer drivers. + - NEW user-defined printers and options. + - NEW persistent jobs and job history + - NEW IPP/1.1 support + - NEW template-based web interfaces. + - NEW CUPS-get-devices and CUPS-get-ppds operations. + - NEW support for create-job and send-file operations. + - NEW certificate-based authentication for local + administration. + - NEW USB backend. + - The lpr command now produces human-readable error messages. + - The lpq command now produces BSD standard format output + instead of OSF/1 output. This should resolve the SAMBA + print queue problems that have been reported. + - The IPP backend did not always detect when the "raw" option + was being used. + - The "lpstat -p" command would stop after the first active + printer. + - The "lpstat -v" command would stop before the first remote + printer. + + +CHANGES IN CUPS v1.0.5 + + - The HP-GL/2 filter did not correctly set the pen color + for pens other than #1. + - The scheduler would only accept 26 simultaneous jobs + under some OS releases (mkstemp() limitation.) It now + handles up to 2^32 simultaneous jobs. + - The PostScript filter loaded the printer's PPD file + twice. + - The PAM authentication code now uses pam_strerror() to + provide a textual error message in the error_log file. + - The scheduler now copies PPD and interface script + files instead of moving them; this fixes installations + with a separate requests directory. + - The PostScript RIP did not generate correct 6-color + output. + - Several filters were marking PPD options twice when + they didn't need to. + - The scheduler did not save the printer or class state + after an accept-jobs or reject-jobs operation. + - The cupsGetDefault() function now ignores the PRINTER + environment variable if it is set to "lp". + - New ippErrorString() function to get textual error + messages. + - Better error reporting in the System V commands. + - The lpadmin and lpstat commands always tried to + connect to the default server. + - The text filter didn't load the charset files from the + correct location. + - Wasn't sending a WWW-Authenticate: field to HTTP + clients when authentication was required. + - httpSeparate() didn't always set the default port + number for known methods. + - The HP-GL/2 filter now looks for "PSwidth,length" + instead of (the correct) "PSlength,width" as + documented by HP. It appears that many major CAD + applications are broken and this change allows the + auto-rotation to work with them. + - The IPP "printer-resolution" option was not being + translated. + - The charset files did not include the Microsoft + "standard" characters from 128 to 159 (unused by the + ISO-8859-x charsets) + - The scheduler was chunking the Content-Type field from + CGI programs; this problem was most noticeable with + Microsoft Internet Explorer 5. + - By popular demand, the printers, jobs, and classes + CGIs no longer force a reload of the page every 10/30 + seconds. + - The scheduler incorrectly required that the IPP client + provide a document-format attribute for the + validate-job operation. + - Clients that sent bad IPP requests without the + required attributes-natural-language and + attributes-charset attributes would crash the + scheduler. + + +CHANGES IN CUPS v1.0.4 + + - Documentation updates. + - Jobs would get stuck in the queue and wouldn't print + until you enabled the queue. + - The lp and lpr commands now catch SIGHUP and SIGINTR. + - The lp and lpr commands now use sigaction or sigset + when available. + - CUPS library updates for WIN32/OS-2 + + +CHANGES IN CUPS v1.0.3 + + - Documentation updates. + - The lpq man page was missing. + - The configure script was not properly detecting the + image libraries. + - The top-level makefile was calling "make" instead of + "$(MAKE)". + - PostScript filter fixes for number-up, OutputOrder, + and %Trailer. + - The imagetops filter didn't end the base-85 encoding + properly if the image data was not a multiple of 4 + bytes in length. + - The imagetoraster filter didn't generate good banded + RGB or CMY data (was dividing the line width by 4 + instead of 3...) + - The imagetoraster filter now records the bounding + box of the image on the page. + - The CUPS image library cache code wasn't working as + designed; images larger than the maximum RIP cache + would eventually thrash using the same cache tile. + - The CUPS image library TIFF loading code didn't + handle unknown resolution units properly; the fixed + code uses a default resolution of 128 PPI. + - cupsGetClasses() and cupsGetPrinters() did not free + existing strings if they ran out of memory. + - The scheduler logs incorrectly contained 3 digits for + the timezone offset instead of 4. + - The scheduler now does a lookup for the default user + and group ID; the previous hardcoded values caused + problems with the LPD backend. + - The cancel-job operation now allows any user in the + system group to cancel any job. + - The cancel-job operation stopped the print queue if + the job was being printed. + - Now only stop printers if the backend fails. If the + filter fails then the failure is noted in the + error_log and printing continues with the next file in + the queue. + - Now log whether a filter fails because of a signal + or because it returned a non-zero exit status. + - The root user now always passes the system group test. + - Printers with an interface script and remote printers + and classes didn't have a printer-make-and-model + attribute. + - Added logging of lost/timed-out remote printers. + - The HP-GL/2 filter was scaling the pen width twice. + - Updated the HP-GL/2 filter to use a single SP (Set + Pen) procedure. This makes the output smaller and is + more appropriate since the filter keeps track of the + pen states already. + - The scheduler didn't handle passwords with spaces. + - The IPP backend now does multiple copies and retries + if the destination server requires it (e.g. HP + JetDirect.) + - The disable command didn't implement the "-c" option + (cancel all jobs.) + - Changed the CMYK generation function for the image file + and PostScript RIPs. + - The lp command didn't support the "-h" option as + documented. + - The AppSocket, IPP, and LPD backends now retry on all + network errors. This should prevent stopped queues + caused by a printer being disconnected from the + network or powered off. + - The scheduler now restarts a job if the corresponding + printer is modified. + - The image RIPs now rotate the image if needed to fit + on the page. + + +CHANGES IN CUPS v1.0.2 + + - The HP-GL/2 filter didn't always scale the output + correctly. + - The HP-GL/2 filter now supports changing the page size + automatically when the "fitplot" option is not used. + - The cancel-job operation was expecting a resource name + of the form "/job/#" instead of "/jobs/#"; this + prevented the cancel and lprm commands from working. + - The backends didn't log pages when files were printed + using the "-oraw" option. + - The authorization code did not work with the Slackware + long shadow password package because its crypt() can + return NULL. + - The chunking code didn't work for reading the response + of a POST request. + - cupsGetPPD() now does authentication as needed. + - The N-up code in the PostScript filter didn't work + with some printers (grestoreall would restore the + default blank page and device settings). + - The N-up code in the PostScript filter didn't scale + the pages to fit within the imageable area of the + page. + - Wasn't doing an fchown() on the request files. This + caused problems when the default root account group + and CUPS group were not the same. + + +CHANGES IN CUPS v1.0.1 + + - Documentation updates. + - Fixed a bunch of possible buffer-overflow conditions. + - The scheduler now supports authentication using PAM. + - Updated the Italian message file. + - httpEncode64() didn't add an extra "=" if there was + only one byte in the last three-byte group. + - Now drop any trailing character set from the locale + string (e.g. "en_US.ISO_8859-1" becomes "en_US") + - Fixed "timezone" vs "tm_gmtoff" usage for BSD-based + operating systems. + - Updated IPP security so that "get" operations can be + done from any resource name; this allows the CGIs to + work with printer authentication enabled so long as + authentication isn't turned on for the whole "site". + - The IPP code didn't properly handle the "unsupported" + group; this caused problems with the HP JetDirect since + it doesn't seem to support the "copies" attribute. + - The HTTP chunking code was missing a CR LF pair at the + end of a 0-length chunk. + - The httpSeparate() function didn't handle embedded + usernames and passwords in the URI properly. + - Doing "lpadmin -p printer -E" didn't restart printing + if there were pending jobs. + - The cancel-job operation now requires either a + requesting-user-name attribute or an authenticated + username. + - The add-printer code did not report errors if the + interface script or PPD file could not be renamed. + - Request files are now created without world read + permissions. + - Added a cupsLastError() function to the CUPS API to + retrieve the IPP error code from the last request. + - Options are now case-insensitive. + - The lpq command now provides 10 characters for the + username instead of the original (Berkeley standard) + 7. + - The cancel command needed a local CUPS server to work + (or the appropriate ServerName in cupsd.conf) + - The cancel and lprm commands didn't report the IPP + error if the job could not be cancelled. + - The lp and lpr commands didn't intercept SIGTERM to + remove temporary files when printing from stdin. + - The lp and lpr commands didn't report the IPP error if + the job could not be printed. diff --git a/CREDITS.txt b/CREDITS.txt new file mode 100644 index 0000000000..71bad14862 --- /dev/null +++ b/CREDITS.txt @@ -0,0 +1,26 @@ +CREDITS.txt - 01/27/2000 +------------------------ + +Few projects are completed by one person, and CUPS is no exception. We'd +like to thank the following individuals for their contributions: + + Nathaniel Barbour - Lots of testing and feedback. + N. Becker - setsid(). + Jean-Eric Cuendet - GhostScript filters for CUPS. + Van Dang - HTTP and IPP policeman. + Dr. ZP Han - setgid()/setuid(). + Guy Harris - *BSD shared libraries and lots of other fixes. + Wang Jian - CUPS RPM corrections. + Roderick Johnstone - Beta tester of the millenium. + Sergey V. Kovalyov - ESP Print Pro and CUPS beta tester. + Mark Lawrence - Microsoft interoperability testing. + Jason McMullan - Original CUPS RPM distributions. + Wes Morgan - *BSD fixes. + Ulrich Oldendorf - German locale. + Petter Reinholdtsen - HP-UX compiler stuff. + Stuart Stevens - HP JetDirect IPP information. + Kiko - Bug fixes. + L. Peter Deutsch - MD5 code. + +If I've missed someone, please let me know by sending an email to +"mike@easysw.com". diff --git a/ENCRYPTION.txt b/ENCRYPTION.txt new file mode 100644 index 0000000000..5ec656ea5f --- /dev/null +++ b/ENCRYPTION.txt @@ -0,0 +1,138 @@ +ENCRYPTION - CUPS v1.1.7 - 02/21/2001 +------------------------------------- + +This file describes the encryption support provided by CUPS. + +WARNING: CLIENTS CURRENTLY TRUST ALL CERTIFICATES FROM SERVERS. +This makes the CUPS client applications vulnerable to "man in +the middle" attacks, so we don't recommend using this to do +remote administration over WANs at this time. + +Future versions of CUPS will keep track of server certificates +and provide a callback/confirmation interface for accepting new +certificates and warning when a certificate has changed. + + +LEGAL STUFF + +BEFORE USING THE ENCRYPTION SUPPORT, PLEASE VERIFY THAT IT IS +LEGAL TO DO SO IN YOUR COUNTRY. CUPS by itself doesn't include +any encryption code, but it can link against the OpenSSL library +which does. + + +OVERVIEW OF ENCRYPTION SUPPORT IN CUPS + +CUPS supports SSL/2.0, SSL/3.0, and TLS/1.0 encryption using +keys as large as 128-bits. Encryption support is provided via +the OpenSSL library and some new hooks in the CUPS code. + +CUPS provides support for dedicated (https) and "upgrade" (TLS) +encryption of sessions. The "HTTP Upgrade" method is described +in RFC 2817; basically, the client can be secure or unsecure, +and the client or server initiates an upgrade to a secure +connection via some new HTTP fields and status codes. The HTTP +Upgrade method is new and no browsers we know of support it yet. +Stick with "https" for web browsers. + +The current implementation is very basic. The CUPS client +software (lp, lpr, etc.) uses encryption as requested by the +user or server. + +The user can specify the "-E" option with the printing commands +to force encryption of the connection. Encryption can also be +specified using the Encryption directive in the client.conf file +or in the CUPS_ENCRYPTION environment variable: + + Never + + Never do encryption. + + Always + + Always do SSL/TLS encryption using the https scheme. + + IfRequested + + Upgrade to TLS encryption if the server asks for it. + This is the default setting. + + Required + + Always upgrade to TLS encryption as soon as the + connection is made. This is different than the "Always" + mode above since the connection is initially unsecure + and the client initiates the upgrade to TLS encryption. + (same as using the "-E" option) + +These keywords are also used in the cupsd.conf file to secure +particular locations. To secure all traffic on the server, listen +on port 443 (https port) instead of port 631 and change the "ipp" +service listing (or add it if you don't have one) in /etc/services +to 443. To provide both secure and normal methods, add a line +reading: + + SSLPort 443 + +to /etc/cups/cupsd.conf. + + +BEFORE YOU BEGIN + +You'll need the OpenSSL library from: + + http://www.openssl.org + + +CONFIGURING WITH ENCRYPTION SUPPORT + +Once you have the OpenSSL library installed, you'll need to +configure CUPS to use it with the "--enable-ssl" option: + + ./configure --enable-ssl + +If the OpenSSL stuff is not in a standard location, make sure to +define the CFLAGS, CXXFLAGS, and LDFLAGS environment variables +with the appropriate compiler and linker options first. + + +GENERATING A SERVER CERTIFICATE AND KEY + +The following OpenSSL command will generate a server certificate +and key that you can play with. Since the certificate is not +properly signed it will generate all kinds of warnings in +Netscape and MSIE: + + openssl req -new -x509 -keyout /etc/cups/ssl/server.key \ + -out /etc/cups/ssl/server.crt -days 365 -nodes + + chmod 600 /etc/cups/ssl/server.* + +The "-nodes" option prevents the certificate and key from being +encrypted. The cupsd process runs in the background, detached +from any input source; if you encrypt these files then cupsd +will not be able to load them! + +Send all rants about non-encrypted certificate and key files to +/dev/null. It makes sense to encrypt user files, but not for +files used by system processes/daemons... + + +REPORTING PROBLEMS + +If you have problems, READ THE DOCUMENTATION FIRST! If the +documentation does not solve your problems please send an email +to "cups-support@cups.org". Include your operating system and +version, compiler and version, and any errors or problems you've +run into. The "/var/log/cups/error_log" file should also be sent, +as it often helps to determine the cause of your problem. + +If you are running a version of Linux, be sure to provide the +Linux distribution you have, too. + +Please note that the "cups-support@cups.org" email address goes +to the CUPS developers; they are busy people, so your email may +go unanswered for days or weeks. In general, only general build +or distribution problems will actually get answered - for +end-user support see the "README.txt" for a summary of the +resources available. diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000000..bcfb5e2654 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,157 @@ +INSTALL - CUPS v1.1.7 - 05/01/2001 +---------------------------------- + +This file describes how to compile and install CUPS from source +code. For more information on CUPS see the file called +"README.txt". A complete change log can be found in +"CHANGES.txt". + + +BEFORE YOU BEGIN + +You'll need ANSI-compliant C and C++ compilers, plus a make +program and Bourne shell. The GNU compiler tools work well - +we've tested the current CUPS code against GCC 2.95.x with +excellent results. + +The makefiles used by the project should work with all versions +of make. We've tested them with GNU make as well as the make +programs shipped by Compaq, HP, SGI, and Sun. FreeBSD users +should use GNU make (gmake). + +Besides these tools you'll want the following libraries: + + - JPEG 6b or higher + - PNG 1.0.6 or higher + - TIFF 3.4 or higher + - ZLIB 1.1.3 or higher + +CUPS will compile and run without these, however you'll miss out on +many of the features provided by CUPS. + + +CONFIGURATION + +CUPS uses GNU autoconf, so you should find the usual "configure" +script in the main CUPS source directory. To configure CUPS for +your system, type: + + ./configure ENTER + +The default installation will put the CUPS software in the +"/etc", "/usr", and "/var" directories on your system, which +will overwrite any existing printing commands on your system. +Use the "--prefix" option to install the CUPS software in +another location: + + ./configure --prefix=/some/directory ENTER + +If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in +a system default location (typically "/usr/include" and +"/usr/lib") you'll need to set the CFLAGS, CXXFLAGS, and LDFLAGS +environment variables prior to running configure: + + setenv CFLAGS "-I/some/directory" ENTER + setenv CXXFLAGS "-I/some/directory" ENTER + setenv LDFLAGS "-L/some/directory" ENTER + ./configure ... ENTER + +or: + + CFLAGS="-I/some/directory"; export CFLAGS ENTER + CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER + LDFLAGS="-L/some/directory"; export LDFLAGS ENTER + ./configure ... ENTER + +To enable support for encryption, you'll also want to add the +"--enable-ssl" option: + + ./configure --enable-ssl + +SSL and TLS support require the OpenSSL library, available at: + + http://www.openssl.org + +See the file "ENCRYPTION.txt" for information on using the +encryption support in CUPS. + +Once you have configured things, just type: + + make ENTER + +or if you have FreeBSD: + + gmake ENTER + +to build the software. + + +INSTALLING THE SOFTWARE + +Once you have built the software you need to install it. The +"install" target provides a quick way to install the software on +your local system: + + make install ENTER + +or for FreeBSD: + + gmake install ENTER + +You can also build binary packages that can be installed on other +machines using the RPM spec file ("cups.spec") or EPM list file +("cups.list"). The latter also supports building of binary RPMs, +so it may be more convenient to use - we use EPM to build all of +our binary distributions. + +You can find the RPM software at: + + http://www.rpm.org + +The RPM software is at: + + http://www.easysw.com/epm + + +CREATING BINARY DISTRIBUTIONS WITH EPM + +The top level makefile supports generation of many types of binary +distributions using EPM. To build a binary distribution type: + + make ENTER + +or + + gmake ENTER + +for FreeBSD, where is one of the following: + + epm - Builds a portable shell script and tar file based + distribution. This format will also backup your + existing printing system if you decide to remove + CUPS at some future time. + rpm - Builds a RPM binary distribution. + deb - Builds a Debian binary distribution. + depot - Builds a HP-UX binary distribution. + pkg - Builds a Solaris binary distribution. + tardist - Builds an IRIX binary distribution. + + +REPORTING PROBLEMS + +If you have problems, READ THE DOCUMENTATION FIRST! If the +documentation does not solve your problems please send an email +to "cups-support@cups.org". Include your operating system and +version, compiler and version, and any errors or problems you've +run into. The "/var/log/cups/error_log" file should also be sent, +as it often helps to determine the cause of your problem. + +If you are running a version of Linux, be sure to provide the +Linux distribution you have, too. + +Please note that the "cups-support@cups.org" email address goes +to the CUPS developers; they are busy people, so your email may +go unanswered for days or weeks. In general, only general build +or distribution problems will actually get answered - for +end-user support see the "README.txt" for a summary of the +resources available. diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000000..1bf924e80a --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,895 @@ + + + Software License Agreement - Common UNIX Printing System + + + + +

Common UNIX Printing System License Agreement

+ +

Copyright 1997-2001 by Easy Software Products
+44141 AIRPORT VIEW DR STE 204
+HOLLYWOOD, MARYLAND 20636-3111 USA
+
+Voice: +1.301.373.9600
+Email: cups-info@cups.org
+WWW: http://www.cups.org + +

Introduction

+ +

The Common UNIX Printing SystemTM, ("CUPSTM"), +is provided under the GNU General Public License ("GPL") and GNU +Library General Public License ("LGPL"), Version 2. A copy of these +licenses follow this introduction. + +

The GNU LGPL applies to the CUPS API library, located in the "cups" +subdirectory of the CUPS source distribution and in the +"/usr/include/cups" directory and "libcups.a", "libcups.sl", or +"libcups.so" files in the binary distributions. + +

The GNU GPL applies to the remainder of the CUPS distribution, +including the "pstoraster" filter which is based upon GNU Ghostscript +5.50 and the "pdftops" filter which is based upon Xpdf 0.90. + +

For those not familiar with the GNU GPL, the license basically +allows you to: + +

    + +
  • Use the CUPS software at no charge. + +
  • Distribute verbatim copies of the software in source or + binary form. + +
  • Sell verbatim copies of the software for a media fee, or + sell support for the software. + +
  • Distribute or sell printer drivers and filters that use + CUPS so long as source code is made available under the GPL. + +
+ +

What this license does not allow you to do is make changes or +add features to CUPS and then sell a binary distribution without source +code. You must provide source for any new drivers, changes, or +additions to the software, and all code must be provided under the GPL +or LGPL as appropriate. + +

The GNU LGPL relaxes the "link-to" restriction, allowing you to +develop applications that use the CUPS API library under other licenses +and/or conditions as appropriate for your application. + +

Trademarks

+ +

Easy Software Products has trademarked the Common UNIX Printing +System, CUPS, and CUPS logo. These names and logos may be used freely +in any direct port or binary distribution of CUPS. To use them in +derivative products, please contract Easy Software Products for written +permission. Our intention is to protect the value of these trademarks and +ensure that any derivative product meets the same high-quality +standards as the original. + +

Binary Distribution Rights

+ +

Easy Software Products also sells rights to the CUPS source code +under a binary distribution license for vendors that are unable to +release source code for their drivers, additions, and modifications to +CUPS under the GNU GPL and LGPL. For information please contact us at +the address shown above. + +

The Common UNIX Printing System provides a "pstoraster" filter that +utilizes the GNU GhostScript 5.50 core to convert PostScript files into +a stream of raster images. For binary distribution licensing of this +software, please contact: + +

+Miles Jones
+Director of Marketing
+Artifex Software Inc.
+454 Las Gallinas Ave., Suite 108
+San Rafael, CA 94903 USA
+Voice: +1.415.492.9861
+Fax: +1.415.492.9862
+EMail: info@arsoft.com +
+ +

The "pdftops" filter is based on the Xpdf 0.90 software. For binary +distribution licensing of this software, please contact: + +

+Derek B. Noonburg
+Email: derekn@foolabs.com
+WWW: http://www.foolabs.com/xpdf/ +
+ +

Support

+ +

Easy Software Products sells software support for CUPS as well as a +commercial printing product based on CUPS called ESP Print Pro. You can +find out more at our web site: + +

+ + +

GNU GENERAL PUBLIC LICENSE

+ +

Version 2, June 1991 + +

+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not allowed.
+
+
+

Preamble

+ +

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +

We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +

The precise terms and conditions for copying, distribution and +modification follow. + +

GNU GENERAL PUBLIC LICENSE
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ +
    + +
  1. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +

  2. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +

    You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +

  3. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +
      + +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +
    2. You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +
    3. if the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) + +
    + +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +

    Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +

    In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +

  4. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +
      + +
    1. Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +
    2. Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +
    3. Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) + +
    + +

    The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +

    If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +

  5. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +
  6. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +
  7. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +
  8. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +

    If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +

    It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +

    This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +

  9. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +
  10. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +

    Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +

  11. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +
+ +

NO WARRANTY

+ +
    + +
  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +
  2. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +
+ +

END OF TERMS AND CONDITIONS

+ + +

GNU LIBRARY GENERAL PUBLIC LICENSE

+ +

Version 2, June 1991 + +

+Copyright (C) 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ +

Preamble

+ +

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +

This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + +

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + +

For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + +

Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + +

Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + +

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +

Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + +

The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + +

Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + +

However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + +

The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + +

Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + +

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ +

0. +This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + +

A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +

The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + +

"Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +

Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + +

1. +You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +

You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +

2. +You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +

    + +
  1. The modified work must itself be a software library. + +

    +

  2. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + +

    +

  3. You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + +

    +

  4. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + +

    (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +

+ +

These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +

Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +

In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +

3. +You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + +

Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +

This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +

4. +You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +

If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +

5. +A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +

However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +

When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + +

If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +

Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +

6. +As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +

You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + +

    + +
  1. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + +

    +

  2. Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + +

    +

  3. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + +

    +

  4. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + +
+ +

For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +

It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +

7. +You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +

    + +
  1. Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + +

    +

  2. Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + +
+ +

8. +You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +

9. +You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +

10. +Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +

11. +If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +

If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +

It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +

This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +

12. +If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + +

13. +The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +

Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +

14. +If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +

NO WARRANTY + +

15. +BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +

16. +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +

END OF TERMS AND CONDITIONS

+ + + diff --git a/Makedefs.in b/Makedefs.in new file mode 100644 index 0000000000..545f3da5c6 --- /dev/null +++ b/Makedefs.in @@ -0,0 +1,169 @@ +# +# "$Id$" +# +# Common makefile definitions for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# +# Programs... +# + +AR = @AR@ +AWK = @AWK@ +CC = @LIBTOOL@ @CC@ +CHMOD = @CHMOD@ +CP = @CP@ +CXX = @LIBTOOL@ @CXX@ +DSO = @DSO@ +HTMLDOC = @HTMLDOC@ +LIBTOOL = @LIBTOOL@ +LN = /bin/ln -sf +MKDIR = @MKDIR@ -p +MV = @MV@ +NROFF = @NROFF@ +RANLIB = @RANLIB@ +RM = @RM@ -f +SED = @SED@ +SHELL = /bin/sh + +# +# Installation programs... +# + +INSTALL_BIN = $(LIBTOOL) $(CP) +INSTALL_DATA = $(CP) +INSTALL_LIB = $(LIBTOOL) $(CP) +INSTALL_MAN = $(CP) +INSTALL_SCRIPT = $(CP) +INSTALL_SYSV = @INSTALL_SYSV@ + +# +# Libraries... +# + +LIBCUPS = @LIBCUPS@ +LIBCUPSIMAGE = @LIBCUPSIMAGE@ +LIBJPEG = @LIBJPEG@ +LIBMALLOC = @LIBMALLOC@ +LIBPNG = @LIBPNG@ +LIBTIFF = @LIBTIFF@ +LIBZ = @LIBZ@ + +# +# Program options... +# +# OPTIM defines the common compiler optimization/debugging options. +# OPTIONS defines other compile-time options (currently only -dDEBUG for +# extra debug info) +# + +ARFLAGS = crvs +CFLAGS = @CFLAGS@ -I.. $(OPTIONS) +CXXFLAGS = @CXXFLAGS@ -I.. $(OPTIONS) +DSOFLAGS = @DSOFLAGS@ +DSOLIBS = @DSOLIBS@ +IMGLIBS = @IMGLIBS@ -lm +LDFLAGS = @LDFLAGS@ $(OPTIM) +LINKCUPS = @LINKCUPS@ +LINKCUPSIMAGE = @LINKCUPSIMAGE@ +LIBS = $(LINKCUPS) $(NETLIBS) @LIBS@ +NETLIBS = @NETLIBS@ +OPTIM = @OPTIM@ +OPTIONS = +SSLLIBS = @SSLLIBS@ + +# +# Directories... +# +# The first section uses the GNU names (which are *extremely* +# difficult to find in a makefile because they are lowercase...) +# We have to define these first because autoconf uses ${prefix} +# and ${exec_prefix} for most of the other directories... +# +# This is immediately followed by definition in ALL CAPS for the +# needed directories... +# + +bindir = @bindir@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +includedir = @includedir@ +infodir = @infodir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +top_srcdir = @top_srcdir@ + +AMANDIR = @AMANDIR@ +BINDIR = @bindir@ +DATADIR = @CUPS_DATADIR@ +DOCDIR = @CUPS_DOCROOT@ +INCLUDEDIR = $(includedir) +INITDIR = @INITDIR@ +INITDDIR = @INITDDIR@ +LIBDIR = $(libdir) +LOCALEDIR = @CUPS_LOCALEDIR@ +LOGDIR = @CUPS_LOGDIR@ +MANDIR = @mandir@ +PAMDIR = @PAMDIR@ +REQUESTS = @CUPS_REQUESTS@ +SBINDIR = @sbindir@ +SERVERBIN = @CUPS_SERVERBIN@ +SERVERROOT = @CUPS_SERVERROOT@ + +CAT1EXT = @CAT1EXT@ +CAT5EXT = @CAT5EXT@ +CAT8EXT = @CAT8EXT@ +MAN8EXT = @MAN8EXT@ + +# +# Rules... +# + +.SILENT: +.SUFFIXES: .a .c .cxx .h .man .o .0 .1 .1m .5 .8 .z +.c.o: + echo Compiling $<... + $(CC) $(OPTIM) $(CFLAGS) -c $< +.cxx.o: + echo Compiling $<... + $(CXX) $(OPTIM) $(CXXFLAGS) -c $< +.man.0 .man.1 .man.1m .man.5 .man.8: + echo Formatting $<... + $(RM) $@ + $(NROFF) -man $< >$@ +.man.z: + echo Formatting $<... + $(RM) $@ t.z + $(NROFF) -man $< >t + pack -f t + $(MV) t.z $@ + +# +# End of "$Id$" +# diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..77f994a740 --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +# +# "$Id$" +# +# Top-level Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include Makedefs + +# +# Directories to make... +# + +DIRS = cups backend berkeley cgi-bin filter man pdftops pstoraster \ + scheduler systemv + +# +# Make all targets... +# + +all: + for dir in $(DIRS); do\ + echo Making all in $$dir... ;\ + (cd $$dir ; $(MAKE) $(MFLAGS)) || exit 1;\ + done + +# +# Remove object and target files... +# + +clean: + for dir in $(DIRS); do\ + echo Cleaning in $$dir... ;\ + (cd $$dir; $(MAKE) $(MFLAGS) clean) || exit 1;\ + done + +# +# Install object and target files... +# + +install: + for dir in $(DIRS); do\ + echo Installing in $$dir... ;\ + (cd $$dir; $(MAKE) $(MFLAGS) install) || exit 1;\ + done + echo Installing in conf... + (cd conf; $(MAKE) $(MFLAGS) install) + echo Installing in data... + (cd data; $(MAKE) $(MFLAGS) install) + echo Installing in doc... + (cd doc; $(MAKE) $(MFLAGS) install) + echo Installing in fonts... + (cd fonts; $(MAKE) $(MFLAGS) install) + echo Installing in locale... + (cd locale; $(MAKE) $(MFLAGS) install) + echo Installing in ppd... + (cd ppd; $(MAKE) $(MFLAGS) install) + echo Installing in templates... + (cd templates; $(MAKE) $(MFLAGS) install) + echo Installing startup script... + if test "x$(INITDIR)" != "x"; then \ + $(MKDIR) $(prefix)/$(INITDIR)/init.d; \ + $(RM) $(prefix)/$(INITDIR)/init.d/cups; \ + $(INSTALL_SCRIPT) cups.sh $(prefix)/$(INITDIR)/init.d/cups; \ + $(CHMOD) ugo+rx $(prefix)/$(INITDIR)/init.d/cups; \ + $(MKDIR) $(prefix)/$(INITDIR)/rc0.d; \ + $(RM) $(prefix)/$(INITDIR)/rc0.d/K00cups; \ + ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc0.d/K00cups; \ + $(MKDIR) $(prefix)/$(INITDIR)/rc2.d; \ + $(RM) $(prefix)/$(INITDIR)/rc2.d/S99cups; \ + ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc2.d/S99cups; \ + $(MKDIR) $(prefix)/$(INITDIR)/rc3.d; \ + $(RM) $(prefix)/$(INITDIR)/rc3.d/S99cups; \ + ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc3.d/S99cups; \ + $(MKDIR) $(prefix)/$(INITDIR)/rc5.d; \ + $(RM) $(prefix)/$(INITDIR)/rc5.d/S99cups; \ + ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc5.d/S99cups; \ + fi + if test "x$(INITDIR)" = "x" -a "x$(INITDDIR)" != "x"; then \ + $(MKDIR) $(prefix)/$(INITDDIR); \ + $(RM) $(prefix)/$(INITDDIR)/cups; \ + $(INSTALL_SCRIPT) cups.sh $(prefix)/$(INITDDIR)/cups; \ + $(CHMOD) ugo+rx $(prefix)/$(INITDDIR)/cups; \ + fi + + +# +# Run the test suite... +# + +test: all + echo Running CUPS test suite... + cd test; ./run-stp-tests.sh + + +# +# Make software distributions using EPM (http://www.easysw.com/epm)... +# + +EPMFLAGS = -v \ + AMANDIR=$(AMANDIR) \ + BINDIR=$(BINDIR) DATADIR=$(DATADIR) \ + DOCDIR=$(DOCDIR) INCLUDEDIR=$(INCLUDEDIR) \ + LIBDIR=$(LIBDIR) LOCALEDIR=$(LOCALEDIR) \ + LOGDIR=$(LOGDIR) MANDIR=$(MANDIR) \ + PAMDIR=$(PAMDIR) REQUESTS=$(REQUESTS) \ + SBINDIR=$(SBINDIR) SERVERBIN=$(SERVERBIN) \ + SERVERROOT=$(SERVERROOT) + +epm: + epm $(EPMFLAGS) cups + +rpm: + epm $(EPMFLAGS) -f rpm cups + +deb: + epm $(EPMFLAGS) -f deb cups + +depot: + epm $(EPMFLAGS) -f depot cups + +pkg: + epm $(EPMFLAGS) -f pkg cups + +tardist: + epm $(EPMFLAGS) -f tardist cups + +# +# End of "$Id$". +# diff --git a/README.txt b/README.txt new file mode 100644 index 0000000000..1dad6ea499 --- /dev/null +++ b/README.txt @@ -0,0 +1,276 @@ +README - CUPS v1.1.7 - 05/01/2001 +--------------------------------- + +Looking for compile instructions? Read the file "INSTALL.txt" +instead... + + +INTRODUCTION + +CUPS provides a portable printing layer for UNIX(r)-based +operating systems. It has been developed by Easy Software +Products to promote a standard printing solution for all UNIX +vendors and users. CUPS provides the System V and Berkeley +command-line interfaces. + +CUPS uses the Internet Printing Protocol ("IPP") as the basis +for managing print jobs and queues. The Line Printer Daemon +("LPD") Server Message Block ("SMB"), and AppSocket (a.k.a. +JetDirect) protocols are also supported with reduced +functionality. CUPS adds network printer browsing and +PostScript Printer Description ("PPD") based printing options to +support real-world printing under UNIX. + +CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP +that are used to support non-PostScript printers. Sample +drivers for HP and EPSON printers are included that use these +filters. + +Drivers for over 2300 printers are provided with our ESP Print +Pro software, available at: + + http://www.easysw.com/printpro + +CUPS is licensed under the GNU General Public License and GNU +Library General Public License. Please contact Easy Software +Products for commercial support and "binary distribution" +rights. + + +SYSTEM REQUIREMENTS + +Binary distributions require a minimum of 10MB of free disk +space. We do not recommend using CUPS on a workstation with less +than 32MB of RAM or a PC with less than 16MB of RAM. + +If you are installing from source you'll need ANSI-compliant C +and C++ compilers and optionally one or more image file support +libraries. Complete source installation instructions can be +found in the file "INSTALL.txt". + + +SOFTWARE REQUIREMENTS + +The following operating system software is required to install +one of the binary distributions from Easy Software Products: + + - Digital UNIX (aka OSF1 aka Compaq Tru64 UNIX) 4.0 or higher + - HP-UX 10.20 or higher + - IRIX 5.3 or higher + - Linux 2.0 with glibc2 or higher + - Solaris 2.5 or higher (SPARC or Intel) + + +INSTALLING "PORTABLE" CUPS DISTRIBUTIONS + +We are currently distributing "portable" CUPS binary +distributions in TAR format with installation and removal +scripts generated by our ESP Package Manager (EPM) software, +which is available from: + + http://www.easysw.com/epm + +WARNING: Installing CUPS will overwrite your existing printing +system. Backup files are made by the installation script and +restored by the removal script, so if you experience problems +you should be able to remove the CUPS software to restore your +previous configuration. However, Easy Software Products makes +no warranty for this and will not be liable for any lost +revenues, etc. + +To install the CUPS software you will need to be logged in as +root (doing an "su" is good enough). Once you are the root +user, run the installation script with: + + ./cups.install ENTER + +After asking you a few yes/no questions the CUPS software will +be installed and the scheduler will be started automatically. + + +INSTALLING HOST-SPECIFIC (RPM, DEBIAN, ETC.) DISTRIBUTIONS + +The host-specific distributions use the operating system +software installation tools. To install a host-specific +distribution please consult the CUPS Software Administrators +Manual or your operating system documentation. + + +READING THE DOCUMENTATION + +Once you have installed the software you can access the +documentation (and a bunch of other stuff) on-line at: + + http://localhost:631 + +If you're having trouble getting that far, the documentation is +located in the "/usr/share/doc/cups" directory in the binary +distributions, and under the "doc" directory in the source +archives. + +Please read the documentation before asking questions. + + +GETTING SUPPORT AND OTHER RESOURCES + +If you have problems, READ THE DOCUMENTATION FIRST! + +You can subscribe to the CUPS mailing list by sending a message +containing "subscribe cups" to majordomo@cups.org. This list is +provided to discuss problems, questions, and improvements to the +CUPS software. New releases of CUPS are announced to this list +as well. + +Commercial support (with a guaranteed response time) is +available from Easy Software Products. For more information +see: + + http://www.easysw.com/cups + +See the CUPS web site at "http://www.cups.org" for other site +links. + + +SETTING UP PRINTER QUEUES USING YOUR WEB BROWSER + +CUPS 1.1 includes a new web-based administration tool that +allows you to manage printers, classes, and jobs on your +server. To access the printer administration tools open the +following URL in your browser: + + http://localhost:631/admin + +You will be asked for the administration password (root or any +other user in the sys/system/root group on your system) and then +shown a menu of available functions. + +DO NOT use the hostname for your machine - it will not work with +the default CUPS configuration. To enable administration access +on other addresses, consult the CUPS Software Administrators +Manual. + + +SETTING UP PRINTER QUEUES FROM THE COMMAND-LINE + +CUPS works best with PPD (PostScript Printer Description) +files. In a pinch you can also use System V style printer +interface scripts. + +Six sample PPD files are provided with this distribution that +utilize the PostScript and image file RIPs and the sample EPSON +and HP printer drivers. To add the sample DeskJet driver to the +system for a printer connected to the parallel port, use one of +the following commands: + + Digital UNIX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp0 -E + + HP-UX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/c2t0d0_lp -E + + IRIX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/plp -E + + Linux: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp0 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp1 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp2 -E + + Solaris: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/bpp0 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/ecpp0 -E + +Similarly, for the other sample drivers you can use: + + Driver PPD File + -------------------------- ------------ + HP DeskJet Series deskjet.ppd + HP LaserJet Series laserjet.ppd + EPSON Stylus Color Series stcolor.ppd + EPSON Stylus Photo Series stphoto.ppd + EPSON 9-pin Series epson9.ppd + EPSON 24-pin Series epson24.ppd + +These sample drivers provide basic printing capabilities, but +generally do not exercise the full potential of the printers or +CUPS. For commercial printer drivers check out our ESP Print +Pro software at: + + http://www.easysw.com/printpro + + +PRINTING FILES + +CUPS provides both the System V "lp" and Berkeley "lpr" commands +for printing: + + lp filename + lpr filename + +Both the "lp" and "lpr" commands support printing options for +the driver: + + lp -omedia=A4 -oresolution=600dpi filename + lpr -omedia=A4 -oresolution=600dpi filename + +CUPS recognizes many types of images files as well as PDF, +PostScript, HP-GL/2, and text files, so you can print those +files directly rather than through an application. + +If you have an application that generates output specifically +for your printer then you need to use the "-oraw" or "-l" +options: + + lp -oraw filename + lpr -l filename + +This will prevent the filters from misinterpreting your print +file. + + +LEGAL STUFF + +CUPS is Copyright 1993-2001 by Easy Software Products. CUPS, +the CUPS logo, and the Common UNIX Printing System are the +trademark property of Easy Software Products. + +The MD5 Digest code is Copyright 1999 Aladdin Enterprises. + +The PostScript RIP software (pstoraster) is based on the GNU +Ghostscript 5.50 core, Copyright 1986-1998 by Aladdin +Enterprises. + +The PDF filter (pdftops) is based on the Xpdf 0.90 software, +Copyright 1996-1999 by Derek B. Noonburg. + +This software is based in part on the work of the Independent +JPEG Group. + +CUPS is provided under the terms of the GNU General Public +License and GNU Library General Public License. This program is +distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the "LICENSE.html", +"LICENSE.txt", or "cups.license" files for more information. + +For commercial licensing information, please contact: + + Attn: CUPS Licensing Information + Easy Software Products + 44141 Airport View Drive, Suite 204 + Hollywood, Maryland 20636-3111 USA + + Voice: +1.301.373.9600 + Email: cups-info@cups.org + WWW: http://www.cups.org + +Note that commercial licensors may also require a license from +Artifex Software Inc. which handles commercial licensing of the +Ghostscript software, and from Derek B. Noonburg who developed +the Xpdf software used to print PDF files. diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 0000000000..90bc265674 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,141 @@ +# +# "$Id$" +# +# Backend makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +BACKENDS = ipp lpd parallel serial socket usb +TARGETS = betest $(BACKENDS) +OBJS = betest.o ipp.o lpd.o parallel.o serial.o socket.o usb.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) http + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERBIN)/backend + $(CHMOD) ugo+rx $(SERVERBIN) + $(CHMOD) ugo+rx $(SERVERBIN)/backend + $(INSTALL_BIN) $(BACKENDS) $(SERVERBIN)/backend + $(RM) $(SERVERBIN)/backend/http + $(LN) ipp $(SERVERBIN)/backend/http + + +# +# betest +# + +betest: betest.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o betest betest.o $(LIBS) + +betest.o: ../cups/string.h ../Makedefs + + +# +# ipp +# + +ipp: ipp.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS) + $(RM) http + $(LN) ipp http + +ipp.o: ../cups/cups.h ../Makedefs + + +# +# lpd +# + +lpd: lpd.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpd lpd.o $(LIBS) + +lpd.o: ../cups/cups.h ../Makedefs + + +# +# parallel +# + +parallel: parallel.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o parallel parallel.o $(LIBS) + +parallel.o: ../cups/cups.h ../Makedefs + + +# +# serial +# + +serial: serial.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o serial serial.o $(LIBS) + +serial.o: ../cups/cups.h ../Makedefs + + +# +# socket +# + +socket: socket.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o socket socket.o $(LIBS) + +socket.o: ../cups/cups.h ../Makedefs + + +# +# usb +# + +usb: usb.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o usb usb.o $(LIBS) + +usb.o: ../cups/cups.h ../Makedefs + + +# +# End of "$Id$". +# diff --git a/backend/betest.c b/backend/betest.c new file mode 100644 index 0000000000..3b7a9b4b04 --- /dev/null +++ b/backend/betest.c @@ -0,0 +1,85 @@ +/* + * "$Id$" + * + * Backend test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Run the named backend. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + + +/* + * 'main()' - Run the named backend. + * + * Usage: + * + * betest device-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (7 or 8) */ + char *argv[]) /* I - Command-line arguments */ +{ + char backend[255]; /* Method in URI */ + + + if (argc < 7 || argc > 8) + { + fputs("Usage: betest device-uri job-id user title copies options [file]\n", + stderr); + return (1); + } + + /* + * Extract the method from the device-uri - that's the program we want to + * execute. + */ + + if (sscanf(argv[1], "%254[^:]", backend) != 1) + { + fputs("betest: Bad device-uri - no colon!\n", stderr); + return (1); + } + + /* + * Execute and return + */ + + execl(backend, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], + NULL); + + return (1); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/ipp.c b/backend/ipp.c new file mode 100644 index 0000000000..43a953330f --- /dev/null +++ b/backend/ipp.c @@ -0,0 +1,614 @@ +/* + * "$Id$" + * + * IPP backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + * password_cb() - Disable the password prompt for cupsDoFileRequest(). + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +const char *password_cb(const char *); + + +/* + * Local globals... + */ + +char *password = NULL; + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + int num_options; /* Number of printer options */ + cups_option_t *options; /* Printer options */ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info */ + resource[1024], /* Resource info (printer name) */ + filename[1024]; /* File to print */ + int port; /* Port number (not used) */ + char uri[HTTP_MAX_URI];/* Updated URI without user/pass */ + ipp_status_t ipp_status; /* Status of IPP request */ + http_t *http; /* HTTP connection */ + ipp_t *request, /* IPP request */ + *response, /* IPP response */ + *supported; /* get-printer-attributes response */ + ipp_attribute_t *job_id_attr; /* job-id attribute */ + int job_id; /* job-id value */ + ipp_attribute_t *job_state; /* job-state attribute */ + ipp_attribute_t *copies_sup; /* copies-supported attribute */ + ipp_attribute_t *charset_sup; /* charset-supported attribute */ + ipp_attribute_t *format_sup; /* document-format-supported attribute */ + const char *charset; /* Character set to use */ + cups_lang_t *language; /* Default language */ + int copies; /* Number of copies remaining */ + const char *content_type; /* CONTENT_TYPE environment variable */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + int version; /* IPP version */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + char *s; + + if ((s = strrchr(argv[0], '/')) != NULL) + s ++; + else + s = argv[0]; + + printf("network %s \"Unknown\" \"Internet Printing Protocol\"\n", s); + return (0); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, copy stdin to a temporary file and print the temporary + * file. + */ + + if (argc == 6) + { + /* + * Copy stdin to a temporary file... + */ + + int fd; /* Temporary file */ + char buffer[8192]; /* Buffer for copying */ + int bytes; /* Number of bytes read */ + + + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) + { + perror("ERROR: unable to create temporary file"); + return (1); + } + + while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) + if (write(fd, buffer, bytes) < bytes) + { + perror("ERROR: unable to write to temporary file"); + close(fd); + unlink(filename); + return (1); + } + + close(fd); + } + else + { + strncpy(filename, argv[6], sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * Set the authentication info, if any... + */ + + cupsSetPasswordCB(password_cb); + + if (username[0]) + { + if ((password = strchr(username, ':')) != NULL) + *password++ = '\0'; + + cupsSetUser(username); + } + + /* + * Try connecting to the remote server... + */ + + do + { + fprintf(stderr, "INFO: Connecting to %s...\n", hostname); + + if ((http = httpConnect(hostname, port)) == NULL) + { + if (errno == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...", + hostname); + sleep(30); + } + else + { + perror("ERROR: Unable to connect to IPP host"); + sleep(30); + } + } + } + while (http == NULL); + + /* + * Build a URI for the printer and fill the standard IPP attributes for + * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it + * might contain username:password information... + */ + + snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource); + + /* + * First validate the destination and see if the device supports multiple + * copies. We have to do this because some IPP servers (e.g. HP JetDirect) + * don't support the copies attribute... + */ + + language = cupsLangDefault(); + charset_sup = NULL; + copies_sup = NULL; + format_sup = NULL; + version = 1; + supported = NULL; + + do + { + /* + * Build the IPP request... + */ + + request = ippNew(); + request->request.op.version[1] = version; + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, "utf-8"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "en"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request... + */ + + if ((supported = cupsDoRequest(http, request, resource)) == NULL) + ipp_status = cupsLastError(); + else + ipp_status = supported->request.status.status_code; + + if (ipp_status > IPP_OK_CONFLICT) + { + if (supported) + ippDelete(supported); + + if (ipp_status == IPP_PRINTER_BUSY || + ipp_status == IPP_SERVICE_UNAVAILABLE) + { + fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr); + sleep(10); + } + else if ((ipp_status == IPP_BAD_REQUEST || + ipp_status == IPP_VERSION_NOT_SUPPORTED) && version == 1) + { + /* + * Switch to IPP/1.0... + */ + + fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n", stderr); + version = 0; + } + else + fprintf(stderr, "ERROR: Printer will not accept print file (%s)!\n", + ippErrorString(ipp_status)); + } + else if ((copies_sup = ippFindAttribute(supported, "copies-supported", + IPP_TAG_RANGE)) != NULL) + { + /* + * Has the "copies-supported" attribute - does it have an upper + * bound > 1? + */ + + if (copies_sup->values[0].range.upper <= 1) + copies_sup = NULL; /* No */ + } + + charset_sup = ippFindAttribute(supported, "charset-supported", + IPP_TAG_CHARSET); + format_sup = ippFindAttribute(supported, "document-format-supported", + IPP_TAG_MIMETYPE); + + if (format_sup) + { + fprintf(stderr, "DEBUG: document-format-supported (%d values)\n", + format_sup->num_values); + for (i = 0; i < format_sup->num_values; i ++) + fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i, + format_sup->values[i].string.text); + } + } + while (ipp_status > IPP_OK_CONFLICT); + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * See if the printer supports multiple copies... + */ + + if (copies_sup) + copies = 1; + else + copies = atoi(argv[4]); + + /* + * Figure out the character set to use... + */ + + charset = language ? cupsLangEncoding(language) : "us-ascii"; + + if (charset_sup) + { + /* + * See if IPP server supports the requested character set... + */ + + for (i = 0; i < charset_sup->num_values; i ++) + if (strcasecmp(charset, charset_sup->values[i].string.text) == 0) + break; + + /* + * If not, choose us-ascii or utf-8... + */ + + if (i >= charset_sup->num_values) + { + /* + * See if us-ascii is supported... + */ + + for (i = 0; i < charset_sup->num_values; i ++) + if (strcasecmp("us-ascii", charset_sup->values[i].string.text) == 0) + break; + + if (i < charset_sup->num_values) + charset = "us-ascii"; + else + charset = "utf-8"; + } + } + + /* + * Then issue the print-job request... + */ + + while (copies > 0) + { + /* + * Build the IPP request... + */ + + request = ippNew(); + request->request.op.version[1] = version; + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, charset); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "en"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, argv[2]); + + fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, + argv[3]); + + fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]); + + /* + * Handle options on the command-line... + */ + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + if ((content_type = getenv("CONTENT_TYPE")) != NULL && format_sup != NULL) + { + for (i = 0; i < format_sup->num_values; i ++) + if (strcasecmp(content_type, format_sup->values[i].string.text) == 0) + break; + + if (i < format_sup->num_values) + num_options = cupsAddOption("document-format", content_type, + num_options, &options); + } + + cupsEncodeOptions(request, num_options, options); + cupsFreeOptions(num_options, options); + + if (copies_sup) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4])); + + /* + * Do the request... + */ + + if ((response = cupsDoFileRequest(http, request, resource, filename)) == NULL) + ipp_status = cupsLastError(); + else + ipp_status = response->request.status.status_code; + + if (ipp_status > IPP_OK_CONFLICT) + { + if (ipp_status == IPP_SERVICE_UNAVAILABLE || + ipp_status == IPP_PRINTER_BUSY) + { + fputs("INFO: Printer is busy; retrying print job...\n", stderr); + sleep(10); + } + else + fprintf(stderr, "ERROR: Print file was not accepted (%s)!\n", + ippErrorString(ipp_status)); + } + else if ((job_id_attr = ippFindAttribute(response, "job-id", + IPP_TAG_INTEGER)) == NULL) + { + fputs("INFO: Print file accepted - job ID unknown.\n", stderr); + job_id = 0; + } + else + { + job_id = job_id_attr->values[0].integer; + fprintf(stderr, "INFO: Print file accepted - job ID %d.\n", job_id); + } + + if (response) + ippDelete(response); + + if (ipp_status <= IPP_OK_CONFLICT) + { + fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1); + copies --; + } + else if (ipp_status != IPP_SERVICE_UNAVAILABLE && + ipp_status != IPP_PRINTER_BUSY) + break; + + /* + * Wait for the job to complete... + */ + + if (!job_id) + continue; + + fputs("INFO: Waiting for job to complete...\n", stderr); + + for (;;) + { + /* + * Build an IPP_GET_JOB_ATTRIBUTES request... + */ + + request = ippNew(); + request->request.op.version[1] = version; + request->request.op.operation_id = IPP_GET_JOB_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, charset); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "en"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", + job_id); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "job-state"); + + /* + * Do the request... + */ + + if ((response = cupsDoRequest(http, request, resource)) == NULL) + ipp_status = cupsLastError(); + else + ipp_status = response->request.status.status_code; + + if (ipp_status > IPP_OK_CONFLICT) + { + if (ipp_status != IPP_SERVICE_UNAVAILABLE && + ipp_status != IPP_PRINTER_BUSY) + { + if (response) + ippDelete(response); + + fprintf(stderr, "ERROR: Unable to get job %d attributes (%s)!\n", + job_id, ippErrorString(ipp_status)); + break; + } + } + else if ((job_state = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) + { + /* + * Stop polling if the job is finished... + */ + + if (job_state->values[0].integer > IPP_JOB_PROCESSING) + { + ippDelete(response); + break; + } + } + + /* + * Wait 10 seconds before polling again... + */ + + if (response) + ippDelete(response); + + sleep(10); + } + } + + /* + * Free memory... + */ + + httpClose(http); + + if (supported) + ippDelete(supported); + + /* + * Close and remove the temporary file if necessary... + */ + + if (argc < 7) + unlink(filename); + + /* + * Return the queue status... + */ + + if (ipp_status <= IPP_OK_CONFLICT) + fputs("INFO: " CUPS_SVERSION " is ready to print.\n", stderr); + + return (ipp_status > IPP_OK_CONFLICT); +} + + +/* + * 'password_cb()' - Disable the password prompt for cupsDoFileRequest(). + */ + +const char * /* O - Password */ +password_cb(const char *prompt) /* I - Prompt (not used) */ +{ + (void)prompt; + + return (password); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/lpd.c b/backend/lpd.c new file mode 100644 index 0000000000..b562b45694 --- /dev/null +++ b/backend/lpd.c @@ -0,0 +1,673 @@ +/* + * "$Id$" + * + * Line Printer Daemon backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + * lpd_command() - Send an LPR command sequence and wait for a reply. + * lpd_queue() - Queue a file using the Line Printer Daemon protocol. + * lpd_write() - Write a buffer of data to an LPD server. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * The order for control and data files in LPD requests... + */ + +#define ORDER_CONTROL_DATA 0 +#define ORDER_DATA_CONTROL 1 + + +/* + * It appears that rresvport() is never declared on most systems... + */ + +extern int rresvport(int *port); + + +/* + * Local functions... + */ + +static int lpd_command(int lpd_fd, char *format, ...); +static int lpd_queue(char *hostname, char *printer, char *filename, + char *user, char *title, int copies, int banner, + int format, int order); +static int lpd_write(int lpd_fd, char *buffer, int length); + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (printer name) */ + *options, /* Pointer to options */ + name[255], /* Name of option */ + value[255], /* Value of option */ + *ptr, /* Pointer into name or value */ + filename[1024], /* File to print */ + title[256]; /* Title string */ + int port; /* Port number (not used) */ + int status; /* Status of LPD job */ + int banner; /* Print banner page? */ + int format; /* Print format */ + int order; /* Order of control/data files */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\""); + return (0); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, copy stdin to a temporary file and print the temporary + * file. + */ + + if (argc == 6) + { + /* + * Copy stdin to a temporary file... + */ + + int fd; /* Temporary file */ + char buffer[8192]; /* Buffer for copying */ + int bytes; /* Number of bytes read */ + + + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) + { + perror("ERROR: unable to create temporary file"); + return (1); + } + + while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) + if (write(fd, buffer, bytes) < bytes) + { + perror("ERROR: unable to write to temporary file"); + close(fd); + unlink(filename); + return (1); + } + + close(fd); + } + else + { + strncpy(filename, argv[6], sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + banner = 0; + format = 'l'; + order = ORDER_CONTROL_DATA; + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + + /* + * Parse options... + */ + + while (*options) + { + /* + * Get the name... + */ + + for (ptr = name; *options && *options != '=';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '+') + options ++; + } + else + value[0] = '\0'; + + /* + * Process the option... + */ + + if (strcasecmp(name, "banner") == 0) + { + /* + * Set the banner... + */ + + banner = !value[0] || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "true") == 0; + } + else if (strcasecmp(name, "format") == 0 && value[0]) + { + /* + * Set output format... + */ + + if (strchr("cdfglnoprtv", value[0]) != NULL) + format = value[0]; + else + fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]); + } + else if (strcasecmp(name, "order") == 0 && value[0]) + { + /* + * Set control/data order... + */ + + if (strcasecmp(value, "control,data") == 0) + order = ORDER_CONTROL_DATA; + else if (strcasecmp(value, "data,control") == 0) + order = ORDER_DATA_CONTROL; + else + fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value); + } + } + } + + /* + * Sanitize the document title... + */ + + strncpy(title, argv[3], sizeof(title) - 1); + title[sizeof(title) - 1] = '\0'; + + for (ptr = title; *ptr; ptr ++) + if (!isalnum(*ptr) && !isspace(*ptr)) + *ptr = '_'; + + /* + * Queue the job... + */ + + if (argc > 6) + { + status = lpd_queue(hostname, resource + 1, filename, + argv[2] /* user */, title, atoi(argv[4]) /* copies */, + banner, format, order); + + if (!status) + fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4])); + } + else + status = lpd_queue(hostname, resource + 1, filename, + argv[2] /* user */, title, 1, banner, format, order); + + /* + * Remove the temporary file if necessary... + */ + + if (argc < 7) + unlink(filename); + + /* + * Return the queue status... + */ + + return (status); +} + + +/* + * 'lpd_command()' - Send an LPR command sequence and wait for a reply. + */ + +static int /* O - Status of command */ +lpd_command(int fd, /* I - Socket connection to LPD host */ + char *format, /* I - printf()-style format string */ + ...) /* I - Additional args as necessary */ +{ + va_list ap; /* Argument pointer */ + char buf[1024]; /* Output buffer */ + int bytes; /* Number of bytes to output */ + char status; /* Status from command */ + + + /* + * Format the string... + */ + + va_start(ap, format); + bytes = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1); + + /* + * Send the command... + */ + + fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes); + + if (lpd_write(fd, buf, bytes) < bytes) + return (-1); + + /* + * Read back the status from the command and return it... + */ + + fprintf(stderr, "DEBUG: Reading command status...\n"); + + if (recv(fd, &status, 1, 0) < 1) + return (-1); + + fprintf(stderr, "DEBUG: lpd_command returning %d\n", status); + + return (status); +} + + +/* + * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol. + */ + +static int /* O - Zero on success, non-zero on failure */ +lpd_queue(char *hostname, /* I - Host to connect to */ + char *printer, /* I - Printer/queue name */ + char *filename, /* I - File to print */ + char *user, /* I - Requesting user */ + char *title, /* I - Job title */ + int copies, /* I - Number of copies */ + int banner, /* I - Print LPD banner? */ + int format, /* I - Format specifier */ + int order) /* I - Order of data/control files */ +{ + FILE *fp; /* Job file */ + char localhost[255]; /* Local host name */ + int error; /* Error number */ + struct stat filestats; /* File statistics */ + int port; /* LPD connection port */ + int fd; /* LPD socket */ + char control[10240], /* LPD control 'file' */ + *cptr; /* Pointer into control file string */ + char status; /* Status byte from command */ + struct sockaddr_in addr; /* Socket address */ + struct hostent *hostaddr; /* Host address */ + size_t nbytes, /* Number of bytes written */ + tbytes; /* Total bytes written */ + char buffer[8192]; /* Output buffer */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * First try to reserve a port for this connection... + */ + + if ((hostaddr = gethostbyname(hostname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s", + hostname, strerror(errno)); + return (1); + } + + fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n", + hostname, printer); + + memset(&addr, 0, sizeof(addr)); + memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + addr.sin_family = hostaddr->h_addrtype; + addr.sin_port = htons(515); /* LPD/printer service */ + + for (port = 732;;) + { + if (getuid()) + { + /* + * We're running as a normal user, so just create a regular socket... + */ + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: Unable to create socket"); + return (1); + } + } + else + { + /* + * We're running as root, so comply with RFC 1179 and reserve a + * priviledged port between 721 and 732... + */ + + if ((fd = rresvport(&port)) < 0) + { + perror("ERROR: Unable to reserve port"); + sleep(30); + continue; + } + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + error = errno; + close(fd); + fd = -1; + + if (error == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...", + hostname); + sleep(30); + } + else if (error == EADDRINUSE) + { + port --; + if (port < 721) + port = 732; + } + else + { + perror("ERROR: Unable to connect to printer"); + sleep(30); + } + } + else + break; + } + + fprintf(stderr, "INFO: Connected from port %d...\n", port); + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Next, open the print file and figure out its size... + */ + + if (stat(filename, &filestats)) + { + perror("ERROR: unable to stat print file"); + return (1); + } + + if ((fp = fopen(filename, "rb")) == NULL) + { + perror("ERROR: unable to open print file for reading"); + return (1); + } + + /* + * Send a job header to the printer, specifying no banner page and + * literal output... + */ + + lpd_command(fd, "\002%s\n", printer); /* Receive print job(s) */ + + gethostname(localhost, sizeof(localhost)); + localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */ + + snprintf(control, sizeof(control), "H%s\nP%s\nJ%s\n", localhost, user, title); + cptr = control + strlen(control); + + if (banner) + { + snprintf(cptr, sizeof(control) - (cptr - control), "L%s\n", user); + cptr += strlen(cptr); + } + + while (copies > 0) + { + snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%s\n", format, + getpid() % 1000, localhost); + cptr += strlen(cptr); + copies --; + } + + snprintf(cptr, sizeof(control) - (cptr - control), + "UdfA%03d%s\nNdfA%03d%s\n", + getpid() % 1000, localhost, + getpid() % 1000, localhost); + + fprintf(stderr, "DEBUG: Control file is:\n%s", control); + + if (order == ORDER_CONTROL_DATA) + { + lpd_command(fd, "\002%d cfA%03.3d%s\n", strlen(control), getpid() % 1000, + localhost); + + fprintf(stderr, "INFO: Sending control file (%d bytes)\n", strlen(control)); + + if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) + { + status = errno; + perror("ERROR: Unable to write control file"); + } + else if (read(fd, &status, 1) < 1) + status = errno; + + if (status != 0) + fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n", + status); + else + fputs("INFO: Control file sent successfully\n", stderr); + } + else + status = 0; + + if (status == 0) + { + /* + * Send the print file... + */ + + lpd_command(fd, "\003%u dfA%03.3d%s\n", (unsigned)filestats.st_size, + getpid() % 1000, localhost); + + fprintf(stderr, "INFO: Sending data file (%u bytes)\n", + (unsigned)filestats.st_size); + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + fprintf(stderr, "INFO: Spooling LPR job, %u%% complete...\n", + (unsigned)(100.0f * tbytes / filestats.st_size)); + + if (lpd_write(fd, buffer, nbytes) < nbytes) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + else + tbytes += nbytes; + } + + if (tbytes < filestats.st_size) + status = errno; + else if (lpd_write(fd, "", 1) < 1) + status = errno; + else if (recv(fd, &status, 1, 0) < 1) + status = errno; + + if (status != 0) + fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n", + status); + else + fputs("INFO: Data file sent successfully\n", stderr); + } + + if (status == 0 && order == ORDER_DATA_CONTROL) + { + lpd_command(fd, "\002%d cfA%03.3d%s\n", strlen(control), getpid() % 1000, + localhost); + + fprintf(stderr, "INFO: Sending control file (%d bytes)\n", strlen(control)); + + if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) + { + status = errno; + perror("ERROR: Unable to write control file"); + } + else if (read(fd, &status, 1) < 1) + status = errno; + + if (status != 0) + fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n", + status); + else + fputs("INFO: Control file sent successfully\n", stderr); + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + fclose(fp); + + return (status); +} + + +/* + * 'lpd_write()' - Write a buffer of data to an LPD server. + */ + +static int /* O - Number of bytes written or -1 on error */ +lpd_write(int lpd_fd, /* I - LPD socket */ + char *buffer, /* I - Buffer to write */ + int length) /* I - Number of bytes to write */ +{ + int bytes, /* Number of bytes written */ + total; /* Total number of bytes written */ + + + total = 0; + while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0) + { + total += bytes; + buffer += bytes; + + if (total == length) + break; + } + + if (bytes < 0) + return (-1); + else + return (length); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/parallel.c b/backend/parallel.c new file mode 100644 index 0000000000..58c1508149 --- /dev/null +++ b/backend/parallel.c @@ -0,0 +1,623 @@ +/* + * "$Id$" + * + * Parallel port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the specified parallel port. + * list_devices() - List all parallel devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the specified parallel port. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options; /* Pointer to options */ + int port; /* Port number (not used) */ + FILE *fp; /* Print file */ + int copies; /* Number of copies to print */ + int fd; /* Parallel device */ + int wbytes; /* Number of bytes written */ + size_t nbytes, /* Number of bytes read */ + tbytes; /* Total number of bytes written */ + char buffer[8192], /* Output buffer */ + *bufptr; /* Pointer into buffer */ + struct termios opts; /* Parallel port options */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (0); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: parallel job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = stdin; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + } + + /* + * Open the parallel port device... + */ + + do + { + if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1) + { + if (errno == EBUSY) + { + fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else + { + perror("ERROR: Unable to open parallel port device file"); + return (1); + } + } + } + while (fd < 0); + + /* + * Set any options provided... + */ + + tcgetattr(fd, &opts); + + opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ + + /**** No options supported yet ****/ + + tcsetattr(fd, TCSANOW, &opts); + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Finally, send the print file... + */ + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * 'list_devices()' - List all parallel devices. + */ + +void +list_devices(void) +{ +#if defined(__hpux) || defined(__sgi) || defined(__sun) + static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz"; + /* Funky hex numbering used for some devices */ +#endif /* __hpux || __sgi || __sun */ + +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255], /* Device filename */ + probefile[255], /* Probe filename */ + basedevice[255]; /* Base device filename for ports */ + FILE *probe; /* /proc/parport/n/autoprobe file */ + char line[1024], /* Line from file */ + *delim, /* Delimiter in file */ + make[IPP_MAX_NAME], /* Make from file */ + model[IPP_MAX_NAME]; /* Model from file */ + + + for (i = 0; i < 4; i ++) + { + /* + * First open the device to make sure the driver module is loaded... + */ + + if ((fd = open("/dev/parallel/0", O_WRONLY)) >= 0) + { + close(fd); + strcpy(basedevice, "/dev/parallel/"); + } + else + { + sprintf(device, "/dev/lp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + strcpy(basedevice, "/dev/lp"); + } + else + { + sprintf(device, "/dev/par%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + strcpy(basedevice, "/dev/par"); + } + else + strcpy(basedevice, "/dev/unknown-parallel"); + } + } + + /* + * Then try looking at the probe file... + */ + + sprintf(probefile, "/proc/parport/%d/autoprobe", i); + if ((probe = fopen(probefile, "r")) == NULL) + { + /* + * Linux 2.4 kernel has different path... + */ + + sprintf(probefile, "/proc/sys/dev/parport/parport%d/autoprobe", i); + probe = fopen(probefile, "r"); + } + + if (probe != NULL) + { + /* + * Found a probe file! + */ + + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + strcpy(model, "Unknown"); + + while (fgets(line, sizeof(line), probe) != NULL) + { + /* + * Strip trailing ; and/or newline. + */ + + if ((delim = strrchr(line, ';')) != NULL) + *delim = '\0'; + else if ((delim = strrchr(line, '\n')) != NULL) + *delim = '\0'; + + /* + * Look for MODEL and MANUFACTURER lines... + */ + + if (strncmp(line, "MODEL:", 6) == 0 && + strncmp(line, "MODEL:Unknown", 13) != 0) + strncpy(model, line + 6, sizeof(model) - 1); + else if (strncmp(line, "MANUFACTURER:", 13) == 0 && + strncmp(line, "MANUFACTURER:Unknown", 20) != 0) + strncpy(make, line + 13, sizeof(make) - 1); + } + + fclose(probe); + + if (make[0]) + printf("direct parallel:%s%d \"%s %s\" \"Parallel Port #%d\"\n", + basedevice, i, make, model, i + 1); + else + printf("direct parallel:%s%d \"%s\" \"Parallel Port #%d\"\n", + basedevice, i, model, i + 1); + } + else if (fd >= 0) + { + /* + * No probe file, but we know the port is there... + */ + + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } +#elif defined(__sgi) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + inventory_t *inv; /* Hardware inventory info */ + + + /* + * IRIX maintains a hardware inventory of most devices... + */ + + setinvent(); + + while ((inv = getinvent()) != NULL) + { + if (inv->inv_class == INV_PARALLEL && + (inv->inv_type == INV_ONBOARD_PLP || + inv->inv_type == INV_EPP_ECP_PLP)) + { + /* + * Standard parallel port... + */ + + puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\""); + } + else if (inv->inv_class == INV_PARALLEL && + inv->inv_type == INV_EPC_PLP) + { + /* + * EPC parallel port... + */ + + printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n", + inv->inv_controller, inv->inv_controller); + } + } + + endinvent(); + + /* + * Central Data makes serial and parallel "servers" that can be + * connected in a number of ways. Look for ports... + */ + + for (i = 0; i < 10; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]); + else if (i == 9) /* PCI */ + sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]); + else /* SCSI */ + sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else if (i == 9) + printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__sun) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard parallel ports... + */ + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/ecpp%d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n", + device, i + 1); + } + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/bpp%d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n", + device, i + 1); + } + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lp%d", i); + + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n", + device, i + 1); + } + + /* + * MAGMA parallel ports... + */ + + for (i = 0; i < 40; i ++) + { + sprintf(device, "/dev/pm%02d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n", + device, (i / 10) + 1, (i % 10) + 1); + } + + /* + * Central Data parallel ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__hpux) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard parallel ports... + */ + + if (access("/dev/rlp", 0) == 0) + puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\""); + + for (i = 0; i < 7; i ++) + for (j = 0; j < 7; j ++) + { + sprintf(device, "/dev/c%dt%dd0_lp", i, j); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n", + device, i, j); + } + + /* + * Central Data parallel ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/lp%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__osf__) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lpt%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + + sprintf(device, "/dev/lpa%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/backend/serial.c b/backend/serial.c new file mode 100644 index 0000000000..19bb7c8819 --- /dev/null +++ b/backend/serial.c @@ -0,0 +1,856 @@ +/* + * "$Id$" + * + * Serial port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + * list_devices() - List all serial devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef __hpux +# include +#endif /* __hpux */ + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif /* HAVE_SYS_IOCTL_H */ +#endif /* WIN32 || __EMX__ */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + +#ifndef CRTSCTS +# ifdef CNEW_RTSCTS +# define CRTSCTS CNEW_RTSCTS +# else +# define CRTSCTS 0 +# endif /* CNEW_RTSCTS */ +#endif /* !CRTSCTS */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options, /* Pointer to options */ + name[255], /* Name of option */ + value[255], /* Value of option */ + *ptr; /* Pointer into name or value */ + int port; /* Port number (not used) */ + FILE *fp; /* Print file */ + int copies; /* Number of copies to print */ + int fd; /* Parallel device */ + int wbytes; /* Number of bytes written */ + size_t nbytes, /* Number of bytes read */ + tbytes; /* Total number of bytes written */ + int dtrdsr; /* Do dtr/dsr flow control? */ + int bufsize; /* Size of output buffer for writes */ + char buffer[8192], /* Output buffer */ + *bufptr; /* Pointer into buffer */ + struct termios opts; /* Parallel port options */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (0); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: serial job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = stdin; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + } + + /* + * Open the serial port device... + */ + + do + { + if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1) + { + if (errno == EBUSY) + { + fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else + { + perror("ERROR: Unable to open serial port device file"); + return (1); + } + } + } + while (fd < 0); + + /* + * Set any options provided... + */ + + tcgetattr(fd, &opts); + + opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ + + bufsize = 480; /* 9600 baud / 10 bits/char / 2Hz */ + dtrdsr = 0; /* No dtr/dsr flow control */ + + if (options != NULL) + while (*options) + { + /* + * Get the name... + */ + + for (ptr = name; *options && *options != '=';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '+') + options ++; + } + else + value[0] = '\0'; + + /* + * Process the option... + */ + + if (strcasecmp(name, "baud") == 0) + { + /* + * Set the baud rate... + */ + + bufsize = atoi(value) / 20; + +#if B19200 == 19200 + cfsetispeed(&opts, atoi(value)); + cfsetospeed(&opts, atoi(value)); +#else + switch (atoi(value)) + { + case 1200 : + cfsetispeed(&opts, B1200); + cfsetospeed(&opts, B1200); + break; + case 2400 : + cfsetispeed(&opts, B2400); + cfsetospeed(&opts, B2400); + break; + case 4800 : + cfsetispeed(&opts, B4800); + cfsetospeed(&opts, B4800); + break; + case 9600 : + cfsetispeed(&opts, B9600); + cfsetospeed(&opts, B9600); + break; + case 19200 : + cfsetispeed(&opts, B19200); + cfsetospeed(&opts, B19200); + break; + case 38400 : + cfsetispeed(&opts, B38400); + cfsetospeed(&opts, B38400); + break; +#ifdef B57600 + case 57600 : + cfsetispeed(&opts, B57600); + cfsetospeed(&opts, B57600); + break; +#endif /* B57600 */ +#ifdef B115200 + case 115200 : + cfsetispeed(&opts, B115200); + cfsetospeed(&opts, B115200); + break; +#endif /* B115200 */ + default : + fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value); + break; + } +#endif /* B19200 == 19200 */ + } + else if (strcasecmp(name, "bits") == 0) + { + /* + * Set number of data bits... + */ + + switch (atoi(value)) + { + case 7 : + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS7; + opts.c_cflag |= PARENB; + opts.c_cflag &= ~PARODD; + break; + case 8 : + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS8; + opts.c_cflag &= ~PARENB; + break; + } + } + else if (strcasecmp(name, "parity") == 0) + { + /* + * Set parity checking... + */ + + if (strcasecmp(value, "even") == 0) + { + opts.c_cflag |= PARENB; + opts.c_cflag &= ~PARODD; + } + else if (strcasecmp(value, "odd") == 0) + { + opts.c_cflag |= PARENB; + opts.c_cflag |= PARODD; + } + else if (strcasecmp(value, "none") == 0) + opts.c_cflag &= ~PARENB; + } + else if (strcasecmp(name, "flow") == 0) + { + /* + * Set flow control... + */ + + if (strcasecmp(value, "none") == 0) + { + opts.c_iflag &= ~(IXON | IXOFF | IXANY); + opts.c_cflag &= ~CRTSCTS; + } + else if (strcasecmp(value, "soft") == 0) + { + opts.c_iflag |= IXON | IXOFF | IXANY; + opts.c_cflag &= ~CRTSCTS; + } + else if (strcasecmp(value, "hard") == 0 || + strcasecmp(value, "rtscts") == 0) + { + opts.c_iflag &= ~(IXON | IXOFF | IXANY); + opts.c_cflag |= CRTSCTS; + } + else if (strcasecmp(value, "dtrdsr") == 0) + { + opts.c_iflag &= ~(IXON | IXOFF | IXANY); + opts.c_cflag &= ~CRTSCTS; + + dtrdsr = 1; + } + } + } + + tcsetattr(fd, TCSANOW, &opts); + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Finally, send the print file... + */ + + if (bufsize > sizeof(buffer)) + bufsize = sizeof(buffer); + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + if (dtrdsr) + { + /* + * Check the port and sleep until DSR is set... + */ + + int status; + + + if (!ioctl(fd, TIOCMGET, &status)) + if (!(status & TIOCM_DSR)) + { + /* + * Wait for DSR to go high... + */ + + fputs("DEBUG: DSR is low; waiting for device...\n", stderr); + + do + { + sleep(1); + if (ioctl(fd, TIOCMGET, &status)) + break; + } + while (!(status & TIOCM_DSR)); + + fputs("DEBUG: DSR is high; writing to device...\n", stderr); + } + } + + tbytes = 0; + while ((nbytes = fread(buffer, 1, bufsize, fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * 'list_devices()' - List all serial devices. + */ + +void +list_devices(void) +{ +#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) + static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz"; + /* Funky hex numbering used for some devices */ +#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ */ + +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 100; i ++) + { + sprintf(device, "/dev/ttyS%d", i); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + } +#elif defined(__sgi) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + inventory_t *inv; /* Hardware inventory info */ + + + /* + * IRIX maintains a hardware inventory of most devices... + */ + + setinvent(); + + while ((inv = getinvent()) != NULL) + { + if (inv->inv_class == INV_SERIAL) + { + /* + * Some sort of serial port... + */ + + if (inv->inv_type == INV_CDSIO || inv->inv_type == INV_CDSIO_E) + { + /* + * CDSIO port... + */ + + for (n = 0; n < 6; n ++) + printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"CDSIO Board %d Serial Port #%d\"\n", + n + 5 + 8 * inv->inv_controller, inv->inv_controller, n + 1); + } + else if (inv->inv_type == INV_EPC_SERIAL) + { + /* + * Everest serial port... + */ + + if (inv->inv_unit == 0) + i = 1; + else + i = 41 + 4 * (int)inv->inv_controller; + + for (n = 0; n < (int)inv->inv_state; n ++) + printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"EPC Serial Port %d, Ebus slot %d\"\n", + n + i, n + 1, (int)inv->inv_controller); + } + else if (inv->inv_state > 1) + { + /* + * Standard serial port under IRIX 6.4 and earlier... + */ + + for (n = 0; n < (int)inv->inv_state; n ++) + printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"Onboard Serial Port %d\"\n", + n + (int)inv->inv_unit + 1, n + (int)inv->inv_unit + 1); + } + else + { + /* + * Standard serial port under IRIX 6.5 and beyond... + */ + + printf("serial serial:/dev/ttyd%d?baud=115200 \"Unknown\" \"Onboard Serial Port %d\"\n", + (int)inv->inv_controller, (int)inv->inv_controller); + } + } + } + + endinvent(); + + /* + * Central Data makes serial and parallel "servers" that can be + * connected in a number of ways. Look for ports... + */ + + for (i = 0; i < 10; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/ttydn%d%c", j, funky_hex[n]); + else if (i == 9) /* PCI */ + sprintf(device, "/dev/ttydp%d%c", j, funky_hex[n]); + else /* SCSI */ + sprintf(device, "/dev/ttyd%d%d%c", i, j, funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else if (i == 9) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data PCI Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__sun) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 26; i ++) + { + sprintf(device, "/dev/cua/%c", 'a' + i); + if (access(device, 0) == 0) +#ifdef B115200 + printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); +#else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); +#endif /* B115200 */ + } + + /* + * MAGMA serial ports... + */ + + for (i = 0; i < 40; i ++) + { + sprintf(device, "/dev/term/%02d", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"MAGMA Serial Board #%d Port #%d\"\n", + device, (i / 10) + 1, (i % 10) + 1); + } + + /* + * Central Data serial ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/sts/ttyN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/sts/tty%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__hpux) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/tty%dp0", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + + /* + * Central Data serial ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/ttyN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/tty%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__osf__) + int i; /* Looping var */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 100; i ++) + { + sprintf(device, "/dev/tty%02d", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + int i, j; /* Looping vars */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + /* + * SIO ports... + */ + + for (i = 0; i < 32; i ++) + { + sprintf(device, "/dev/ttyd%c", funky_hex[i]); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Standard Serial Port #%d\"\n", + device, i + 1); + } + } + + /* + * Cyclades ports... + */ + + for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ + for (j = 0; j < 32; j ++) + { + sprintf(device, "/dev/ttyc%d%c", i, funky_hex[j]); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n", + device, i, j + 1); + } + } + + /* + * Digiboard ports... + */ + + for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ + for (j = 0; j < 32; j ++) + { + sprintf(device, "/dev/ttyD%d%c", i, funky_hex[j]); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Digiboard #%d Serial Port #%d\"\n", + device, i, j + 1); + } + } + + /* + * Stallion ports... + */ + + for (i = 0; i < 32; i ++) + { + sprintf(device, "/dev/ttyE%c", funky_hex[i]); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Stallion Serial Port #%d\"\n", + device, i + 1); + } + } + + /* + * SX ports... + */ + + for (i = 0; i < 128; i ++) + { + sprintf(device, "/dev/ttyA%d", i + 1); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n", + device, i + 1); + } + } +#elif defined(__NetBSD__) + int i, j; /* Looping vars */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 4; i ++) + { + sprintf(device, "/dev/tty%02d", i); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + } + + /* + * Cyclades-Z ports... + */ + + for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ + for (j = 0; j < 64; j ++) + { + sprintf(device, "/dev/ttyCZ%02d%02d", i, j); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Prt #%d\"\n", + device, i, j + 1); + } + } + +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/backend/socket.c b/backend/socket.c new file mode 100644 index 0000000000..38305a67a2 --- /dev/null +++ b/backend/socket.c @@ -0,0 +1,343 @@ +/* + * "$Id$" + * + * AppSocket backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024]; /* Resource info (not used) */ + FILE *fp; /* Print file */ + int copies; /* Number of copies to print */ + int port; /* Port number */ + int delay; /* Delay for retries... */ + int fd; /* AppSocket */ + int error; /* Error code (if any) */ + struct sockaddr_in addr; /* Socket address */ + struct hostent *hostaddr; /* Host address */ + int wbytes; /* Number of bytes written */ + size_t nbytes, /* Number of bytes read */ + tbytes; /* Total number of bytes written */ + char buffer[8192], /* Output buffer */ + *bufptr; /* Pointer into buffer */ + struct timeval timeout; /* Timeout for select() */ + fd_set input; /* Input set for select() */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\""); + return (0); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = stdin; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the hostname and port number from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + if (port == 0) + port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */ + + /* + * Then try to connect to the remote host... + */ + + if ((hostaddr = gethostbyname(hostname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n", + hostname, strerror(errno)); + return (1); + } + + fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n", + hostname, port); + + memset(&addr, 0, sizeof(addr)); + memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + addr.sin_family = hostaddr->h_addrtype; + addr.sin_port = htons(port); + + while (copies > 0) + { + for (delay = 5;;) + { + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: Unable to create socket"); + return (1); + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + error = errno; + close(fd); + fd = -1; + + if (error == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in %d seconds...\n", + hostname, delay); + sleep(delay); + + if (delay < 30) + delay += 5; + } + else + { + perror("ERROR: Unable to connect to printer (retrying in 30 seconds)"); + sleep(30); + } + } + else + break; + } + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Finally, send the print file... + */ + + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + fputs("INFO: Connected to host, sending print job...\n", stderr); + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + /* + * Check for possible data coming back from the printer... + */ + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO(&input); + FD_SET(fd, &input); +#ifdef __hpux + if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0) +#else + if (select(fd + 1, &input, NULL, NULL, &timeout) > 0) +#endif /* __hpux */ + { + /* + * Grab the data coming back and spit it out to stderr... + */ + + if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0) + fprintf(stderr, "INFO: Received %u bytes of back-channel data!\n", + nbytes); + } + else if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + + /* + * Shutdown the socket and wait for the other end to finish... + */ + + fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr); + + shutdown(fd, 1); + + for (;;) + { + /* + * Wait a maximum of 90 seconds for backchannel data or a closed + * connection... + */ + + timeout.tv_sec = 90; + timeout.tv_usec = 0; + + FD_ZERO(&input); + FD_SET(fd, &input); + +#ifdef __hpux + if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0) +#else + if (select(fd + 1, &input, NULL, NULL, &timeout) > 0) +#endif /* __hpux */ + { + /* + * Grab the data coming back and spit it out to stderr... + */ + + if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0) + fprintf(stderr, "INFO: Received %u bytes of back-channel data!\n", + nbytes); + else + break; + } + else + break; + } + + /* + * Close the socket connection... + */ + + close(fd); + } + + /* + * Close the input file and return... + */ + + if (fp != stdin) + fclose(fp); + + fputs("INFO: " CUPS_SVERSION " is ready to print.\n", stderr); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/usb.c b/backend/usb.c new file mode 100644 index 0000000000..78050cb635 --- /dev/null +++ b/backend/usb.c @@ -0,0 +1,437 @@ +/* + * "$Id$" + * + * USB port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the specified USB port. + * list_devices() - List all USB devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the specified USB port. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options; /* Pointer to options */ + int port; /* Port number (not used) */ + FILE *fp; /* Print file */ + int copies; /* Number of copies to print */ + int fd; /* Parallel device */ + int wbytes; /* Number of bytes written */ + size_t nbytes, /* Number of bytes read */ + tbytes; /* Total number of bytes written */ + char buffer[8192], /* Output buffer */ + *bufptr; /* Pointer into buffer */ + struct termios opts; /* Parallel port options */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (0); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: USB job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = stdin; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + } + + /* + * Open the USB port device... + */ + + do + { + if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1) + { + if (errno == EBUSY) + { + fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else + { + perror("ERROR: Unable to open USB port device file"); + return (1); + } + } + } + while (fd < 0); + + /* + * Set any options provided... + */ + + tcgetattr(fd, &opts); + + opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ + + /**** No options supported yet ****/ + + tcsetattr(fd, TCSANOW, &opts); + + /* + * Now that we are "connected" to the port, ignore SIGTERM so that we + * can finish out any page data the driver sends (e.g. to eject the + * current page... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGTERM, &action, NULL); +#else + signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Finally, send the print file... + */ + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * 'list_devices()' - List all USB devices. + */ + +void +list_devices(void) +{ +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + FILE *probe; /* /proc/bus/usb/devices file */ + char line[1024], /* Line from file */ + *delim, /* Delimiter in file */ + make[IPP_MAX_NAME], /* Make from file */ + model[IPP_MAX_NAME]; /* Model from file */ + + + /* + * First try opening one of the USB devices to load the driver + * module as needed... + */ + + if ((fd = open("/dev/usb/lp0", O_WRONLY)) >= 0) + close(fd); /* 2.3.x and 2.4.x */ + else if ((fd = open("/dev/usb/usblp0", O_WRONLY)) >= 0) + close(fd); /* Mandrake 7.x */ + else if ((fd = open("/dev/usblp0", O_WRONLY)) >= 0) + close(fd); /* 2.2.x */ + + /* + * Then look at the device list for the USB bus... + */ + + if ((probe = fopen("/proc/bus/usb/devices", "r")) != NULL) + { + /* + * Scan the device list... + */ + + i = 0; + + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + + while (fgets(line, sizeof(line), probe) != NULL) + { + /* + * Strip trailing newline. + */ + + if ((delim = strrchr(line, '\n')) != NULL) + *delim = '\0'; + + /* + * See if it is a printer device ("P: ...") + */ + + if (strncmp(line, "S:", 2) == 0) + { + /* + * String attribute... + */ + + if (strncmp(line, "S: Manufacturer=", 17) == 0) + { + strncpy(make, line + 17, sizeof(make) - 1); + if (strcmp(make, "Hewlett-Packard") == 0) + strcpy(make, "HP"); + } + else if (strncmp(line, "S: Product=", 12) == 0) + strncpy(model, line + 12, sizeof(model) - 1); + } + else if (strncmp(line, "I:", 2) == 0 && + (strstr(line, "Driver=printer") != NULL || + strstr(line, "Driver=usblp") != NULL) && + make[0] && model[0]) + { + /* + * We were processing a printer device; send the info out... + */ + + sprintf(device, "/dev/usb/lp%d", i); + if (access(device, 0)) + { + sprintf(device, "/dev/usb/usblp%d", i); + + if (access(device, 0)) + sprintf(device, "/dev/usblp%d", i); + } + + printf("direct usb:%s \"%s %s\" \"USB Printer #%d\"\n", + device, make, model, i + 1); + + i ++; + + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + } + } + + fclose(probe); + } + else + { + /* + * Just probe manually for USB devices... + */ + + for (i = 0; i < 8; i ++) + { + sprintf(device, "/dev/usb/lp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); + } + + sprintf(device, "/dev/usb/usblp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); + } + + sprintf(device, "/dev/usblp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); + } + } + } +#elif defined(__sgi) +#elif defined(__sun) +#elif defined(__hpux) +#elif defined(__osf) +#elif defined(__FreeBSD__) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/unlpt%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Port #%d\"\n", device, i + 1); + } + } +#elif defined(__NetBSD__) || defined(__OpenBSD__) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/ulpt%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Port #%d\"\n", device, i + 1); + } + } +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/Makefile b/berkeley/Makefile new file mode 100644 index 0000000000..76571d46bd --- /dev/null +++ b/berkeley/Makefile @@ -0,0 +1,105 @@ +# +# "$Id$" +# +# Berkeley commands makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +TARGETS = lpc lpq lpr lprm +OBJS = lpc.o lpq.o lpr.o lprm.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(BINDIR) + $(CHMOD) ugo+rx $(BINDIR) + $(INSTALL_BIN) lpq lpr lprm $(BINDIR) + -$(MKDIR) $(SBINDIR) + $(CHMOD) ugo+rx $(SBINDIR) + $(INSTALL_BIN) lpc $(SBINDIR) + + +# +# lpc +# + +lpc: lpc.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpc lpc.o $(LIBS) + +lpc.o: ../cups/cups.h ../Makedefs + + +# +# lpq +# + +lpq: lpq.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpq lpq.o $(LIBS) + +lpq.o: ../cups/cups.h ../Makedefs + + +# +# lpr +# + +lpr: lpr.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpr lpr.o $(LIBS) + +lpr.o: ../cups/cups.h ../Makedefs + + +# +# lprm +# + +lprm: lprm.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lprm lprm.o $(LIBS) + +lprm.o: ../cups/cups.h ../Makedefs + + +# +# End of "$Id$". +# diff --git a/berkeley/lpc.c b/berkeley/lpc.c new file mode 100644 index 0000000000..71d56c49e0 --- /dev/null +++ b/berkeley/lpc.c @@ -0,0 +1,481 @@ +/* + * "$Id$" + * + * "lpc" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * compare_strings() - Compare two command-line strings. + * do_command() - Do an lpc command... + * show_help() - Show help messages. + * show_status() - Show printers. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int compare_strings(char *, char *, int); +static void do_command(http_t *, char *, char *); +static void show_help(char *); +static void show_status(http_t *, char *); + + +/* + * 'main()' - Parse options and commands. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* Connection to server */ + char line[1024], /* Input line from user */ + *params; /* Pointer to parameters */ + + + /* + * Connect to the scheduler... + */ + + http = httpConnect(cupsServer(), ippPort()); + + if (argc > 1) + { + /* + * Process a single command on the command-line... + */ + + do_command(http, argv[1], argv[2]); + } + else + { + /* + * Do the command prompt thing... + */ + + printf("lpc> "); + while (fgets(line, sizeof(line), stdin) != NULL) + { + /* + * Strip the trailing newline... + */ + + line[strlen(line) - 1] = '\0'; + + /* + * Find any options in the string... + */ + + while (isspace(line[0])) + strcpy(line, line + 1); + + for (params = line; *params != '\0'; params ++) + if (isspace(*params)) + break; + + /* + * Remove whitespace between the command and parameters... + */ + + while (isspace(*params)) + *params++ = '\0'; + + /* + * The "quit" and "exit" commands exit; otherwise, process as needed... + */ + + if (compare_strings(line, "quit", 1) == 0 || + compare_strings(line, "exit", 2) == 0) + break; + + if (*params == '\0') + do_command(http, line, NULL); + else + do_command(http, line, params); + + /* + * Put another prompt out to the user... + */ + + printf("lpc> "); + } + } + + /* + * Close the connection to the server and return... + */ + + httpClose(http); + + return (0); +} + + +/* + * 'compare_strings()' - Compare two command-line strings. + */ + +static int /* O - -1 or 1 = no match, 0 = match */ +compare_strings(char *s, /* I - Command-line string */ + char *t, /* I - Option string */ + int tmin) /* I - Minimum number of unique chars in option */ +{ + int slen; /* Length of command-line string */ + + + slen = strlen(s); + if (slen < tmin) + return (-1); + else + return (strncmp(s, t, slen)); +} + + +/* + * 'do_command()' - Do an lpc command... + */ + +static void +do_command(http_t *http, /* I - HTTP connection to server */ + char *command, /* I - Command string */ + char *params) /* I - Parameters for command */ +{ + if (compare_strings(command, "status", 4) == 0) + show_status(http, params); + else if (compare_strings(command, "help", 1) == 0 || + strcmp(command, "?") == 0) + show_help(params); + else + printf("%s is not implemented by the CUPS version of lpc.\n", command); +} + + +/* + * 'show_help()' - Show help messages. + */ + +static void +show_help(char *command) /* I - Command to describe or NULL */ +{ + if (command == NULL) + { + puts("Commands may be abbreviated. Commands are:"); + puts(""); + puts("exit help quit status ?"); + } + else if (compare_strings(command, "help", 1) == 0 || + strcmp(command, "?") == 0) + puts("help\t\tget help on commands"); + else if (compare_strings(command, "status", 4) == 0) + puts("status\t\tshow status of daemon and queue"); + else + puts("?Invalid help command unknown"); +} + + +/* + * 'show_status()' - Show printers. + */ + +static void +show_status(http_t *http, /* I - HTTP connection to server */ + char *dests) /* I - Destinations */ +{ + ipp_t *request, /* IPP Request */ + *response, /* IPP Response */ + *jobs; /* IPP Get Jobs response */ + ipp_attribute_t *attr, /* Current attribute */ + *jattr; /* Current job attribute */ + cups_lang_t *language; /* Default language */ + char *printer, /* Printer name */ + *device; /* Device URI */ + ipp_pstate_t pstate; /* Printer state */ + int accepting; /* Is printer accepting jobs? */ + int jobcount; /* Count of current jobs */ + char *dptr, /* Pointer into destination list */ + *ptr; /* Pointer into printer name */ + int match; /* Non-zero if this job matches */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + static const char *requested[] = + { /* Requested attributes */ + "printer-name", + "device-uri", + "printer-state", + "printer-is-accepting-jobs" + }; + + + DEBUG_printf(("show_status(%08x, %08x)\n", http, dests)); + + if (http == NULL) + return; + + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", sizeof(requested) / sizeof(requested[0]), + NULL, requested); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/printers/")) != NULL) + { + DEBUG_puts("show_status: request succeeded..."); + + /* + * Loop through the printers returned in the list and display + * their status... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + printer = NULL; + device = "file:/dev/null"; + pstate = IPP_PRINTER_IDLE; + jobcount = 0; + accepting = 1; + + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (strcmp(attr->name, "device-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + device = attr->values[0].string.text; + + if (strcmp(attr->name, "printer-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + pstate = (ipp_pstate_t)attr->values[0].integer; + + if (strcmp(attr->name, "printer-is-accepting-jobs") == 0 && + attr->value_tag == IPP_TAG_BOOLEAN) + accepting = attr->values[0].boolean; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (printer == NULL) + { + if (attr == NULL) + break; + else + continue; + } + + /* + * See if this is a printer we're interested in... + */ + + match = dests == NULL; + + if (dests != NULL) + { + for (dptr = dests; *dptr != '\0';) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*dptr) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && *ptr == *dptr; + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr) && *dptr != '\0') + dptr ++; + while (isspace(*dptr) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + /* + * Display the printer entry if needed... + */ + + if (match) + { + /* + * If the printer state is "IPP_PRINTER_PROCESSING", then grab the + * current job for the printer. + */ + + if (pstate == IPP_PRINTER_PROCESSING) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * limit + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, + cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language->language); + + snprintf(printer_uri, sizeof(printer_uri), + "ipp://localhost/printers/%s", printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "job-id"); + + if ((jobs = cupsDoRequest(http, request, "/jobs/")) != NULL) + { + for (jattr = jobs->attrs; jattr != NULL; jattr = jattr->next) + if (jattr->name && strcmp(jattr->name, "job-id") == 0) + jobcount ++; + + ippDelete(jobs); + } + } + + /* + * Display it... + */ + + printf("%s:\n", printer); + if (strncmp(device, "file:", 5) == 0) + printf("\tprinter is on device \'%s\' speed -1\n", device + 5); + else + { + /* + * Just show the method... + */ + + *strchr(device, ':') = '\0'; + printf("\tprinter is on device \'%s\' speed -1\n", device); + } + + printf("\tqueuing is %sabled\n", accepting ? "en" : "dis"); + printf("\tprinting is %sabled\n", + pstate == IPP_PRINTER_STOPPED ? "dis" : "en"); + if (jobcount == 0) + puts("\tno entries"); + else + printf("\t%d entries\n", jobcount); + puts("\tdaemon present"); + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lpq.c b/berkeley/lpq.c new file mode 100644 index 0000000000..91de680858 --- /dev/null +++ b/berkeley/lpq.c @@ -0,0 +1,539 @@ +/* + * "$Id$" + * + * "lpq" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * show_jobs() - Show jobs. + * show_printer() - Show printer status. + */ + +/* + * Include necessary headers... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int show_jobs(http_t *, const char *, const char *, const int, + const int); +static void show_printer(http_t *, const char *); + + +/* + * 'main()' - Parse options and commands. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* Connection to server */ + const char *dest, /* Desired printer */ + *user; /* Desired user */ + char *instance; /* Printer instance */ + int id, /* Desired job ID */ + interval, /* Reporting interval */ + longstatus; /* Show file details */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + http_encryption_t encryption; /* Encryption? */ + + + /* + * Connect to the scheduler... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + fputs("lpq: Unable to contact server!\n", stderr); + return (1); + } + + /* + * Check for command-line options... + */ + + dest = NULL; + user = NULL; + id = 0; + interval = 0; + longstatus = 0; + + num_dests = cupsGetDests(&dests); + + for (i = 0; i < num_dests; i ++) + if (dests[i].is_default) + dest = dests[i].name; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '+') + interval = atoi(argv[i] + 1); + else if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_LIBSSL + encryption = HTTP_ENCRYPT_REQUIRED; + + if (http) + httpEncryption(http, encryption); +#else + fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n", + argv[0]); +#endif /* HAVE_LIBSSL */ + break; + + case 'P' : /* Printer */ + if (argv[i][2]) + dest = argv[i] + 2; + else + { + i ++; + dest = argv[i]; + } + + if ((instance = strchr(dest, '/')) != NULL) + *instance = '\0'; + break; + + case 'a' : /* All printers */ + dest = NULL; + break; + + case 'l' : /* Long status */ + longstatus = 1; + break; + + default : + fputs("Usage: lpq [-P dest] [-l] [+interval]\n", stderr); + httpClose(http); + cupsFreeDests(num_dests, dests); + return (1); + } + } + else if (isdigit(argv[i][0])) + id = atoi(argv[i]); + else + user = argv[i]; + + /* + * Show the status in a loop... + */ + + for (;;) + { + if (dest) + show_printer(http, dest); + + i = show_jobs(http, dest, user, id, longstatus); + + if (i && interval) + { + fflush(stdout); + sleep(interval); + } + else + break; + } + + /* + * Close the connection to the server and return... + */ + + cupsFreeDests(num_dests, dests); + httpClose(http); + + return (0); +} + + +/* + * 'show_jobs()' - Show jobs. + */ + +static int /* O - Number of jobs in queue */ +show_jobs(http_t *http, /* I - HTTP connection to server */ + const char *dest, /* I - Destination */ + const char *user, /* I - User */ + const int id, /* I - Job ID */ + const int longstatus)/* I - 1 if long report desired */ +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + const char *jobdest, /* Pointer into job-printer-uri */ + *jobuser, /* Pointer to job-originating-user-name */ + *jobname; /* Pointer to job-name */ + ipp_jstate_t jobstate; /* job-state */ + int jobid, /* job-id */ + jobsize, /* job-k-octets */ +#ifdef __osf__ + jobpriority, /* job-priority */ +#endif /* __osf__ */ + jobcount, /* Number of jobs */ + jobcopies, /* Number of copies */ + rank; /* Rank of job */ + char resource[1024]; /* Resource string */ + char rankstr[255]; /* Rank string */ + char namestr[1024]; /* Job name string */ + static const char *ranks[10] =/* Ranking strings */ + { + "th", + "st", + "nd", + "rd", + "th", + "th", + "th", + "th", + "th", + "th" + }; + + + DEBUG_printf(("show_jobs(%08x, %08x, %08x, %d, %d)\n", http, dest, user, id, + longstatus)); + + if (http == NULL) + return (0); + + /* + * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires + * the following attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri or printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (dest == NULL) + { + if (id) + sprintf(resource, "ipp://localhost/jobs/%d", id); + else + strcpy(resource, "ipp://localhost/jobs"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, resource); + } + else + { + snprintf(resource, sizeof(resource), "ipp://localhost/printers/%s", dest); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, resource); + } + + if (user) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + + /* + * Do the request and get back a response... + */ + + jobcount = 0; + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpq: get-jobs failed: %s\n", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (0); + } + + rank = 1; + + /* + * Loop through the job list and display them... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + jobid = 0; + jobsize = 0; +#ifdef __osf__ + jobpriority = 50; +#endif /* __osf__ */ + jobstate = IPP_JOB_PENDING; + jobname = "untitled"; + jobuser = NULL; + jobdest = NULL; + jobcopies = 1; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobid = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobsize = attr->values[0].integer * 1024; + +#ifdef __osf__ + if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobpriority = attr->values[0].integer; +#endif /* __osf__ */ + + if (strcmp(attr->name, "job-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + jobstate = (ipp_jstate_t)attr->values[0].integer; + + if (strcmp(attr->name, "job-printer-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL) + jobdest ++; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + jobuser = attr->values[0].string.text; + + if (strcmp(attr->name, "job-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + jobname = attr->values[0].string.text; + + if (strcmp(attr->name, "copies") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobcopies = attr->values[0].integer; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (jobdest == NULL || jobid == 0) + { + if (attr == NULL) + break; + else + continue; + } + + if (!longstatus && jobcount == 0) +#ifdef __osf__ + puts("Rank Owner Pri Job Files Total Size"); +#else + puts("Rank Owner Job File(s) Total Size"); +#endif /* __osf__ */ + + jobcount ++; + + /* + * Display the job... + */ + + if (jobstate == IPP_JOB_PROCESSING) + strcpy(rankstr, "active"); + else + { + snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]); + rank ++; + } + + if (longstatus) + { + puts(""); + + if (jobcopies > 1) + snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies, + jobname); + else + { + strncpy(namestr, jobname, sizeof(namestr) - 1); + namestr[sizeof(namestr) - 1] = '\0'; + } + + printf("%s: %-34.34s[job %d localhost]\n", jobuser, rankstr, jobid); + printf(" %-40.40s%d bytes\n", namestr, jobsize); + } + else +#ifdef __osf__ + printf("%-6s %-10.10s %-4d %-10d %-27.27s %d bytes\n", rankstr, jobuser, + jobpriority, jobid, jobname, jobsize); +#else + printf("%-7s %-8.8s%-8d%-32.32s%d bytes\n", rankstr, jobuser, + jobid, jobname, jobsize); +#endif /* __osf */ + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + fprintf(stderr, "lpq: get-jobs failed: %s\n", ippErrorString(cupsLastError())); + return (0); + } + + if (jobcount == 0) + puts("no entries"); + + return (jobcount); +} + + +/* + * 'show_printer()' - Show printer status. + */ + +static void +show_printer(http_t *http, /* I - HTTP connection to server */ + const char *dest) /* I - Destination */ +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + ipp_pstate_t state; /* Printer state */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + + + if (http == NULL) + return; + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", dest); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpq: get-printer-attributes failed: %s\n", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return; + } + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + state = (ipp_pstate_t)attr->values[0].integer; + else + state = IPP_PRINTER_STOPPED; + + switch (state) + { + case IPP_PRINTER_IDLE : + printf("%s is ready\n", dest); + break; + case IPP_PRINTER_PROCESSING : + printf("%s is ready and printing\n", dest); + break; + case IPP_PRINTER_STOPPED : + printf("%s is not ready\n", dest); + break; + } + + ippDelete(response); + } + else + fprintf(stderr, "lpq: get-printer-attributes failed: %s\n", + ippErrorString(cupsLastError())); +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lpr.c b/berkeley/lpr.c new file mode 100644 index 0000000000..c268c94c05 --- /dev/null +++ b/berkeley/lpr.c @@ -0,0 +1,425 @@ +/* + * "$Id$" + * + * "lpr" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and send files for printing. + * sighandler() - Signal catcher for when we print from stdin... + */ + +/* + * Include necessary headers... + */ + +#include +#include + +#include +#include + + +#ifndef WIN32 +# include + + +/* + * Local functions. + */ + +void sighandler(int); +#endif /* !WIN32 */ + + +/* + * Globals... + */ + +char tempfile[1024]; /* Temporary file for printing from stdin */ + + +/* + * 'main()' - Parse options and send files for printing. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j; /* Looping var */ + int job_id; /* Job ID */ + char ch; /* Option character */ + char *printer, /* Destination printer or class */ + *instance; /* Instance */ + const char *title; /* Job title */ + int num_copies; /* Number of copies per file */ + int num_files; /* Number of files to print */ + const char *files[1000]; /* Files to print */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests, /* Destinations */ + *dest; /* Selected destination */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + int deletefile; /* Delete file after print? */ + char buffer[8192]; /* Copy buffer */ + int temp; /* Temporary file descriptor */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Signal action */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + deletefile = 0; + printer = NULL; + num_dests = 0; + dests = NULL; + num_options = 0; + options = NULL; + num_files = 0; + title = NULL; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (ch = argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_LIBSSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); +#else + fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n", + argv[0]); +#endif /* HAVE_LIBSSL */ + break; + + case '1' : /* TROFF font set 1 */ + case '2' : /* TROFF font set 2 */ + case '3' : /* TROFF font set 3 */ + case '4' : /* TROFF font set 4 */ + case 'i' : /* indent */ + case 'w' : /* width */ + if (argv[i][2] == '\0') + { + i ++; + + if (i >= argc) + { + fprintf(stderr, "lpr: Expected value after -%c option!\n", ch); + return (1); + } + } + + case 'c' : /* CIFPLOT */ + case 'd' : /* DVI */ + case 'f' : /* FORTRAN */ + case 'g' : /* plot */ + case 'n' : /* Ditroff */ + case 't' : /* Troff */ + case 'v' : /* Raster image */ + fprintf(stderr, "Warning: \'%c\' format modifier not supported - output may not be correct!\n", + ch); + break; + + case 'o' : /* Option */ + if (argv[i][2] != '\0') + num_options = cupsParseOptions(argv[i] + 2, num_options, &options); + else + { + i ++; + if (i >= argc) + { + fputs("lpr: Expected option=value after -o option!\n", stderr); + return (1); + } + + num_options = cupsParseOptions(argv[i], num_options, &options); + } + break; + + case 'l' : /* Literal/raw */ + num_options = cupsAddOption("raw", "", num_options, &options); + break; + + case 'p' : /* Prettyprint */ + num_options = cupsAddOption("prettyprint", "", num_options, &options); + break; + + case 'h' : /* Suppress burst page */ + num_options = cupsAddOption("job-sheets", "none", num_options, &options); + break; + + case 's' : /* Don't use symlinks */ + break; + + case 'm' : /* Mail on completion */ + fputs("Warning: email notification is not supported!\n", stderr); + break; + + case 'q' : /* Queue file but don't print */ + num_options = cupsAddOption("job-hold-until", "indefinite", + num_options, &options); + break; + + case 'r' : /* Remove file after printing */ + deletefile = 1; + break; + + case 'P' : /* Destination printer or class */ + if (argv[i][2] != '\0') + printer = argv[i] + 2; + else + { + i ++; + if (i >= argc) + { + fputs("lpr: Expected destination after -P option!\n", stderr); + return (1); + } + + printer = argv[i]; + } + + if ((instance = strrchr(printer, '/')) != NULL) + *instance++ = '\0'; + + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL) + { + for (j = 0; j < dest->num_options; j ++) + if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) + num_options = cupsAddOption(dest->options[j].name, + dest->options[j].value, + num_options, &options); + } + break; + + case '#' : /* Number of copies */ + if (argv[i][2] != '\0') + num_copies = atoi(argv[i] + 2); + else + { + i ++; + if (i >= argc) + { + fputs("lpr: Expected copy count after -# option!\n", stderr); + return (1); + } + + num_copies = atoi(argv[i]); + } + + if (num_copies < 1 || num_copies > 100) + { + fputs("lpr: Number copies must be between 1 and 100.\n", stderr); + return (1); + } + + sprintf(buffer, "%d", num_copies); + num_options = cupsAddOption("copies", buffer, num_options, &options); + break; + + case 'C' : /* Class */ + case 'J' : /* Job name */ + case 'T' : /* Title */ + if (argv[i][2] != '\0') + title = argv[i] + 2; + else + { + i ++; + if (i >= argc) + { + fprintf(stderr, "lpr: Expected name after -%c option!\n", ch); + return (1); + } + + title = argv[i]; + } + break; + + case 'U' : /* User */ + if (argv[i][2] != '\0') + cupsSetUser(argv[i] + 2); + else + { + i ++; + if (i >= argc) + { + fputs("lpr: Expected username after -U option!\n", stderr); + return (1); + } + + cupsSetUser(argv[i]); + } + break; + + default : + fprintf(stderr, "lpr: Unknown option \'%c\'!\n", argv[i][1]); + return (1); + } + else if (num_files < 1000) + { + /* + * Print a file... + */ + + files[num_files] = argv[i]; + num_files ++; + + if (title == NULL) + { + if ((title = strrchr(argv[i], '/')) != NULL) + title ++; + else + title = argv[i]; + } + } + else + fprintf(stderr, "lpr: Too many files - \"%s\"\n", argv[i]); + /* + * See if we have any files to print; if not, print from stdin... + */ + + if (printer == NULL) + { + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + for (j = 0, dest = dests; j < num_dests; j ++, dest ++) + if (dest->is_default) + { + printer = dests[j].name; + + for (j = 0; j < dest->num_options; j ++) + if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) + num_options = cupsAddOption(dest->options[j].name, + dest->options[j].value, + num_options, &options); + break; + } + } + + if (printer == NULL) + { + fputs("lpr: error - no default destination available.\n", stderr); + return (1); + } + + if (num_files > 0) + { + job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options); + + if (deletefile) + { + /* + * Delete print files after printing... + */ + + for (i = 0; i < num_files; i ++) + unlink(files[i]); + } + } + else + { + num_files = 1; + +#ifndef WIN32 +# if defined(HAVE_SIGSET) + sigset(SIGHUP, sighandler); + sigset(SIGINT, sighandler); + sigset(SIGTERM, sighandler); +# elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = sighandler; + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +# else + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); +# endif +#endif /* !WIN32 */ + + if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + fputs("lpr: unable to create temporary file.\n", stderr); + return (1); + } + + while ((i = fread(buffer, 1, sizeof(buffer), stdin)) > 0) + write(temp, buffer, i); + + i = lseek(temp, 0, SEEK_CUR); + close(temp); + + if (i == 0) + { + fputs("lpr: stdin is empty, so no job has been sent.\n", stderr); + return (1); + } + + if (title) + job_id = cupsPrintFile(printer, tempfile, title, num_options, options); + else + job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options); + + unlink(tempfile); + } + + if (job_id < 1) + { + fprintf(stderr, "lpr: unable to print file: %s\n", + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +#ifndef WIN32 +/* + * 'sighandler()' - Signal catcher for when we print from stdin... + */ + +void +sighandler(int s) /* I - Signal number */ +{ + /* + * Remove the temporary file we're using to print from stdin... + */ + + unlink(tempfile); + + /* + * Exit... + */ + + exit(s); +} +#endif /* !WIN32 */ + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lprm.c b/berkeley/lprm.c new file mode 100644 index 0000000000..1241de57ee --- /dev/null +++ b/berkeley/lprm.c @@ -0,0 +1,269 @@ +/* + * "$Id$" + * + * "lprm" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and cancel jobs. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include +#include + + +/* + * 'main()' - Parse options and cancel jobs. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* HTTP connection to server */ + int i; /* Looping var */ + int job_id; /* Job ID */ + const char *dest; /* Destination printer */ + char *instance; /* Pointer to instance name */ + char uri[1024]; /* Printer or job URI */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_op_t op; /* Operation */ + cups_lang_t *language; /* Language */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + http_encryption_t encryption; /* Encryption? */ + + + /* + * Setup to cancel individual print jobs... + */ + + op = IPP_CANCEL_JOB; + job_id = 0; + dest = NULL; + response = NULL; + http = NULL; + encryption = cupsEncryption(); + + num_dests = cupsGetDests(&dests); + + for (i = 0; i < num_dests; i ++) + if (dests[i].is_default) + dest = dests[i].name; + + /* + * Open a connection to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + fputs("lprm: Unable to contact server!\n", stderr); + cupsFreeDests(num_dests, dests); + return (1); + } + + httpEncryption(http, encryption); + + /* + * Process command-line arguments... + */ + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-' && argv[i][1] != '\0') + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_LIBSSL + encryption = HTTP_ENCRYPT_REQUIRED; + + httpEncryption(http, encryption); +#else + fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n", + argv[0]); +#endif /* HAVE_LIBSSL */ + break; + + case 'P' : /* Cancel jobs on a printer */ + if (argv[i][2]) + dest = argv[i] + 2; + else + { + i ++; + dest = argv[i]; + } + + if ((instance = strchr(dest, '/')) != NULL) + *instance = '\0'; + break; + + default : + fprintf(stderr, "lprm: Unknown option \'%c\'!\n", argv[i][1]); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + else + { + /* + * Cancel a job or printer... + */ + + if (isdigit(argv[i][0])) + { + dest = NULL; + op = IPP_CANCEL_JOB; + job_id = atoi(argv[i]); + } + else if (strcmp(argv[i], "-") == 0) + { + /* + * Cancel all jobs + */ + + op = IPP_PURGE_JOBS; + } + else + { + dest = argv[i]; + job_id = 0; + } + + /* + * Build an IPP request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + job-id *or* job-uri + * [requesting-user-name] + */ + + request = ippNew(); + + request->request.op.operation_id = op; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (dest) + { + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", dest); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", + job_id); + } + else + { + sprintf(uri, "ipp://localhost/jobs/%d", job_id); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, + uri); + } + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + if (op == IPP_PURGE_JOBS) + response = cupsDoRequest(http, request, "/admin/"); + else + response = cupsDoRequest(http, request, "/jobs/"); + + if (response != NULL) + { + switch (response->request.status.status_code) + { + case IPP_NOT_FOUND : + fputs("lprm: Job or printer not found!\n", stderr); + break; + case IPP_NOT_AUTHORIZED : + fputs("lprm: Not authorized to lprm job(s)!\n", stderr); + break; + case IPP_FORBIDDEN : + fprintf(stderr, "lprm: You don't own job ID %d!\n", job_id); + break; + default : + if (response->request.status.status_code > IPP_OK_CONFLICT) + fputs("lprm: Unable to lprm job(s)!\n", stderr); + break; + } + + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + ippDelete(response); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + + ippDelete(response); + } + else + { + fputs("lprm: Unable to cancel job(s)!\n", stderr); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + } + + /* + * If nothing has been cancelled yet, cancel the current job on the specified + * (or default) printer... + */ + + if (response == NULL) + if (!cupsCancelJob(dest, 0)) + { + fputs("lprm: Unable to cancel job(s)!\n", stderr); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + + cupsFreeDests(num_dests, dests); + httpClose(http); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile new file mode 100644 index 0000000000..29c9268371 --- /dev/null +++ b/cgi-bin/Makefile @@ -0,0 +1,121 @@ +# +# "$Id$" +# +# CGI makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +CGIS = admin.cgi classes.cgi jobs.cgi printers.cgi +TARGETS = libcgi.a $(CGIS) +LIBOBJS = html.o ipp-var.o template.o var.o +OBJS = $(LIBOBJS) admin.o classes.o jobs.o printers.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERBIN)/cgi-bin + $(CHMOD) ugo+rx $(SERVERBIN) + $(CHMOD) ugo+rx $(SERVERBIN)/cgi-bin + $(INSTALL_BIN) $(CGIS) $(SERVERBIN)/cgi-bin + + +# +# libcgi.a +# + +libcgi.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +$(LIBOBJS): cgi.h +ipp-var.o: ipp-var.h + + +# +# admin.cgi +# + +admin.cgi: admin.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ admin.o libcgi.a $(LIBS) + +admin.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# classes.cgi +# + +classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ classes.o libcgi.a $(LIBS) + +classes.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# jobs.cgi +# + +jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ jobs.o libcgi.a $(LIBS) + +jobs.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# printers.cgi +# + +printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ printers.o libcgi.a $(LIBS) + +printers.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + +$(OBJS): ../Makedefs + + +# +# End of "$Id$". +# diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c new file mode 100644 index 0000000000..c00c1d7b85 --- /dev/null +++ b/cgi-bin/admin.c @@ -0,0 +1,1598 @@ +/* + * "$Id$" + * + * Administration CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * do_am_class() - Add or modify a class. + * do_am_printer() - Add or modify a printer. + * do_config_printer() - Configure the default options for a printer. + * do_delete_class() - Delete a class... + * do_delete_printer() - Delete a printer... + * do_job_op() - Do a job operation. + * do_printer_op() - Do a printer operation. + * get_line() - Get a line that is terminated by a LF, CR, or CR LF. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" +#include +#include + + +/* + * Local functions... + */ + +static void do_am_class(http_t *http, cups_lang_t *language, int modify); +static void do_am_printer(http_t *http, cups_lang_t *language, int modify); +static void do_config_printer(http_t *http, cups_lang_t *language); +static void do_delete_class(http_t *http, cups_lang_t *language); +static void do_delete_printer(http_t *http, cups_lang_t *language); +static void do_job_op(http_t *http, cups_lang_t *language, ipp_op_t op); +static void do_printer_op(http_t *http, cups_lang_t *language, ipp_op_t op); +static char *get_line(char *buf, int length, FILE *fp); + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + http_t *http; /* Connection to the server */ + const char *op; /* Operation name */ + + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Send a standard header... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + cgiSetVariable("TITLE", "Admin"); + ippSetServerVersion(); + + cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG")); + + /* + * See if we have form data... + */ + + if (!cgiInitialize()) + { + /* + * Nope, send the administration menu... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "admin.tmpl", getenv("LANG")); + } + else if ((op = cgiGetVariable("OP")) != NULL) + { + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Do the operation... + */ + + if (strcmp(op, "cancel-job") == 0) + do_job_op(http, language, IPP_CANCEL_JOB); + else if (strcmp(op, "hold-job") == 0) + do_job_op(http, language, IPP_HOLD_JOB); + else if (strcmp(op, "release-job") == 0) + do_job_op(http, language, IPP_RELEASE_JOB); + else if (strcmp(op, "restart-job") == 0) + do_job_op(http, language, IPP_RESTART_JOB); + else if (strcmp(op, "start-printer") == 0) + do_printer_op(http, language, IPP_RESUME_PRINTER); + else if (strcmp(op, "stop-printer") == 0) + do_printer_op(http, language, IPP_PAUSE_PRINTER); + else if (strcmp(op, "accept-jobs") == 0) + do_printer_op(http, language, CUPS_ACCEPT_JOBS); + else if (strcmp(op, "reject-jobs") == 0) + do_printer_op(http, language, CUPS_REJECT_JOBS); + else if (strcmp(op, "add-class") == 0) + do_am_class(http, language, 0); + else if (strcmp(op, "add-printer") == 0) + do_am_printer(http, language, 0); + else if (strcmp(op, "modify-class") == 0) + do_am_class(http, language, 1); + else if (strcmp(op, "modify-printer") == 0) + do_am_printer(http, language, 1); + else if (strcmp(op, "delete-class") == 0) + do_delete_class(http, language); + else if (strcmp(op, "delete-printer") == 0) + do_delete_printer(http, language); + else if (strcmp(op, "config-printer") == 0) + do_config_printer(http, language); + else + { + /* + * Bad operation code... Display an error... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "admin-op.tmpl", getenv("LANG")); + } + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + } + else + { + /* + * Form data but no operation code... Display an error... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "admin-op.tmpl", getenv("LANG")); + } + + /* + * Send the standard trailer... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG")); + + /* + * Free the request language... + */ + + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'do_am_class()' - Add or modify a class. + */ + +static void +do_am_class(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + int modify) /* I - Modify the printer? */ +{ + int i, j; /* Looping vars */ + int element; /* Element number */ + int num_printers; /* Number of printers */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* member-uris attribute */ + ipp_status_t status; /* Request status */ + char uri[HTTP_MAX_URI]; /* Device or printer URI */ + const char *name, /* Pointer to class name */ + *ptr; /* Pointer to CGI variable */ + + + if (cgiGetVariable("PRINTER_LOCATION") == NULL) + { + if (modify) + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + } + + /* + * Update the location and description of an existing printer... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "modify-class.tmpl", getenv("LANG")); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "add-class.tmpl", getenv("LANG")); + } + + return; + } + + name = cgiGetVariable("PRINTER_NAME"); + if (isdigit(*name)) + ptr = name; + else + for (ptr = name; *ptr; ptr ++) + if (!isalnum(*ptr) && *ptr != '_') + break; + + if (*ptr || ptr == name) + { + cgiSetVariable("ERROR", "The class name may only contain letters, " + "numbers, and the underscore."); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + if (cgiGetVariable("MEMBER_URIS") == NULL) + { + /* + * Build a CUPS_GET_PRINTERS request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Create MEMBER_URIS and MEMBER_NAMES arrays... + */ + + for (element = 0, attr = response->attrs; + attr != NULL; + attr = attr->next) + if (attr->name && strcmp(attr->name, "printer-uri-supported") == 0) + { + cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text); + element ++; + } + + for (element = 0, attr = response->attrs; + attr != NULL; + attr = attr->next) + if (attr->name && strcmp(attr->name, "printer-name") == 0) + { + cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text); + element ++; + } + + num_printers = cgiGetSize("MEMBER_URIS"); + + ippDelete(response); + } + else + num_printers = 0; + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) + { + /* + * Mark any current members in the class... + */ + + for (j = 0; j < num_printers; j ++) + cgiSetArray("MEMBER_SELECTED", j, ""); + + for (i = 0; i < attr->num_values; i ++) + for (j = 0; j < num_printers; j ++) + if (strcmp(attr->values[i].string.text, cgiGetArray("MEMBER_URIS", j)) == 0) + { + cgiSetArray("MEMBER_SELECTED", j, "SELECTED"); + break; + } + } + + ippDelete(response); + } + + /* + * Let the user choose... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-members.tmpl", getenv("LANG")); + } + else + { + /* + * Build a CUPS_ADD_CLASS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * printer-location + * printer-info + * printer-is-accepting-jobs + * printer-state + * member-uris + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_ADD_CLASS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", + NULL, cgiGetVariable("PRINTER_LOCATION")); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", + NULL, cgiGetVariable("PRINTER_INFO")); + + ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); + + ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + IPP_PRINTER_IDLE); + + if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0) + { + attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", + num_printers, NULL, NULL); + for (i = 0; i < num_printers; i ++) + attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i)); + } + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + ippDelete(response); + } + else + status = IPP_NOT_AUTHORIZED; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else if (modify) + cgiCopyTemplateLang(stdout, TEMPLATES, "class-modified.tmpl", getenv("LANG")); + else + cgiCopyTemplateLang(stdout, TEMPLATES, "class-added.tmpl", getenv("LANG")); + } +} + + +/* + * 'do_am_printer()' - Add or modify a printer. + */ + +static void +do_am_printer(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + int modify) /* I - Modify the printer? */ +{ + int i; /* Looping var */ + int element; /* Element number */ + ipp_attribute_t *attr, /* Current attribute */ + *last; /* Last attribute */ + ipp_t *request, /* IPP request */ + *response, /* IPP response */ + *oldinfo; /* Old printer information */ + ipp_status_t status; /* Request status */ + const char *var; /* CGI variable */ + char uri[HTTP_MAX_URI], /* Device or printer URI */ + *uriptr; /* Pointer into URI */ + int maxrate; /* Maximum baud rate */ + char baudrate[255]; /* Baud rate string */ + char make[255]; /* Make string */ + const char *name, /* Pointer to class name */ + *ptr; /* Pointer to CGI variable */ + static int baudrates[] = /* Baud rates */ + { + 1200, + 2400, + 4800, + 9600, + 19200, + 38400, + 57600, + 115200, + 230400, + 460800 + }; + + + if (modify) + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + oldinfo = cupsDoRequest(http, request, "/"); + } + else + oldinfo = NULL; + + if ((name = cgiGetVariable("PRINTER_NAME")) == NULL) + { + if (modify) + { + /* + * Update the location and description of an existing printer... + */ + + if (oldinfo) + ippSetCGIVars(oldinfo, NULL, NULL); + + cgiCopyTemplateLang(stdout, TEMPLATES, "modify-printer.tmpl", getenv("LANG")); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "add-printer.tmpl", getenv("LANG")); + } + + if (oldinfo) + ippDelete(oldinfo); + + return; + } + + if (isdigit(*name)) + ptr = name; + else + for (ptr = name; *ptr; ptr ++) + if (!isalnum(*ptr) && *ptr != '_') + break; + + if (*ptr || ptr == name) + { + cgiSetVariable("ERROR", "The printer name may only contain letters, " + "numbers, and the underscore."); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + if ((var = cgiGetVariable("DEVICE_URI")) == NULL) + { + /* + * Build a CUPS_GET_DEVICES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_DEVICES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + } + + /* + * Let the user choose... + */ + + if (oldinfo && + (attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) + { + strncpy(uri, attr->values[0].string.text, sizeof(uri) - 1); + uri[sizeof(uri) - 1] = '\0'; + if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) + *uriptr = '\0'; + + cgiSetVariable("CURRENT_DEVICE_URI", uri); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-device.tmpl", getenv("LANG")); + } + else if (strchr(var, '/') == NULL) + { + if (oldinfo && + (attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) + { + /* + * Set the current device URI for the form to the old one... + */ + + if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0) + cgiSetVariable("DEVICE_URI", attr->values[0].string.text); + } + + /* + * User needs to set the full URI... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-uri.tmpl", getenv("LANG")); + } + else if (strncmp(var, "serial:", 7) == 0 && cgiGetVariable("BAUDRATE") == NULL) + { + /* + * Need baud rate, parity, etc. + */ + + if ((var = strchr(var, '?')) != NULL && + strncmp(var, "?baud=", 6) == 0) + maxrate = atoi(var + 6); + else + maxrate = 19200; + + for (i = 0; i < 10; i ++) + if (baudrates[i] > maxrate) + break; + else + { + sprintf(baudrate, "%d", baudrates[i]); + cgiSetArray("BAUDRATES", i, baudrate); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-serial.tmpl", getenv("LANG")); + } + else if ((var = cgiGetVariable("PPD_NAME")) == NULL) + { + if (modify) + { + /* + * Get the PPD file... + */ + + int fd; /* PPD file */ + char filename[1024]; /* PPD filename */ + ppd_file_t *ppd; /* PPD information */ + char buffer[1024]; /* Buffer */ + int bytes; /* Number of bytes */ + + + snprintf(uri, sizeof(uri), "/printers/%s.ppd", name); + + if (httpGet(http, uri)) + httpGet(http, uri); + + while (httpUpdate(http) == HTTP_CONTINUE); + + if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0) + { + while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + write(fd, buffer, bytes); + + close(fd); + + if ((ppd = ppdOpenFile(filename)) != NULL) + { + if (ppd->manufacturer) + cgiSetVariable("CURRENT_MAKE", ppd->manufacturer); + if (ppd->nickname) + cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname); + + ppdClose(ppd); + } + + unlink(filename); + } + else + httpFlush(http); + } + + /* + * Build a CUPS_GET_PPDS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PPDS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((var = cgiGetVariable("PPD_MAKE")) == NULL) + { + /* + * Let the user choose a make... + */ + + for (element = 0, attr = response->attrs, last = NULL; + attr != NULL; + attr = attr->next) + if (attr->name && strcmp(attr->name, "ppd-make") == 0) + if (last == NULL || + strcasecmp(last->values[0].string.text, + attr->values[0].string.text) != 0) + { + cgiSetArray("PPD_MAKE", element, attr->values[0].string.text); + element ++; + last = attr; + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-make.tmpl", + getenv("LANG")); + } + else + { + /* + * Let the user choose a model... + */ + + strncpy(make, var, sizeof(make) - 1); + make[sizeof(make) - 1] = '\0'; + + ippSetCGIVars(response, "ppd-make", make); + cgiCopyTemplateLang(stdout, TEMPLATES, "choose-model.tmpl", + getenv("LANG")); + } + + ippDelete(response); + } + else + { + char message[1024]; + + + snprintf(message, sizeof(message), "Unable to get list of printer drivers: %s", + ippErrorString(cupsLastError())); + cgiSetVariable("ERROR", message); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + } + else + { + /* + * Build a CUPS_ADD_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * printer-location + * printer-info + * ppd-name + * device-uri + * printer-is-accepting-jobs + * printer-state + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_ADD_PRINTER; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", + NULL, cgiGetVariable("PRINTER_LOCATION")); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", + NULL, cgiGetVariable("PRINTER_INFO")); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", + NULL, cgiGetVariable("PPD_NAME")); + + strncpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri) - 1); + uri[sizeof(uri) - 1] = '\0'; + if (strncmp(uri, "serial:", 7) == 0) + { + /* + * Update serial port URI to include baud rate, etc. + */ + + if ((uriptr = strchr(uri, '?')) == NULL) + uriptr = uri + strlen(uri); + + snprintf(uriptr, sizeof(uri) - (uriptr - uri), + "?baud=%s+bits=%s+parity=%s+flow=%s", + cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"), + cgiGetVariable("PARITY"), cgiGetVariable("FLOW")); + } + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", + NULL, uri); + + ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); + + ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + IPP_PRINTER_IDLE); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + ippDelete(response); + } + else + status = IPP_NOT_AUTHORIZED; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else if (modify) + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-modified.tmpl", getenv("LANG")); + else + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-added.tmpl", getenv("LANG")); + } + + if (oldinfo) + ippDelete(oldinfo); +} + + +/* + * 'do_config_printer()' - Configure the default options for a printer. + */ + +static void +do_config_printer(http_t *http, /* I - HTTP connection */ + cups_lang_t *language)/* I - Client's language */ +{ + int i, j, k; /* Looping vars */ + int have_options; /* Have options? */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *var; /* Variable value */ + const char *printer; /* Printer printer name */ + ipp_status_t status; /* Operation status... */ + const char *filename; /* PPD filename */ + char tempfile[1024]; /* Temporary filename */ + FILE *in, /* Input file */ + *out; /* Output file */ + int outfd; /* Output file descriptor */ + char line[1024]; /* Line from PPD file */ + char keyword[1024], /* Keyword from Default line */ + *keyptr; /* Pointer into keyword... */ + ppd_file_t *ppd; /* PPD file */ + ppd_group_t *group; /* Option group */ + ppd_option_t *option; /* Option */ + + + /* + * Get the printer name... + */ + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + /* + * Get the PPD file... + */ + + if ((filename = cupsGetPPD(printer)) == NULL) + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + ppd = ppdOpenFile(filename); + + if (cgiGetVariable("job_sheets_start") != NULL || + cgiGetVariable("job_sheets_end") != NULL) + have_options = 1; + else + have_options = 0; + + for (i = ppd->num_groups, group = ppd->groups; + i > 0 && !have_options; + i --, group ++) + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + if ((var = cgiGetVariable(option->keyword)) != NULL) + { + have_options = 1; + break; + } + + if (!have_options) + { + /* + * Show the options to the user... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "config-printer.tmpl", + getenv("LANG")); + + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + cgiSetVariable("GROUP", group->text); + cgiCopyTemplateLang(stdout, TEMPLATES, "option-header.tmpl", + getenv("LANG")); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + if (strcmp(option->keyword, "PageRegion") == 0) + continue; + + cgiSetVariable("KEYWORD", option->keyword); + cgiSetVariable("KEYTEXT", option->text); + cgiSetVariable("DEFCHOICE", option->defchoice); + + cgiSetSize("CHOICES", option->num_choices); + cgiSetSize("TEXT", option->num_choices); + for (k = 0; k < option->num_choices; k ++) + { + cgiSetArray("CHOICES", k, option->choices[k].choice); + cgiSetArray("TEXT", k, option->choices[k].text); + } + + switch (option->ui) + { + case PPD_UI_BOOLEAN : + cgiCopyTemplateLang(stdout, TEMPLATES, "option-boolean.tmpl", + getenv("LANG")); + break; + case PPD_UI_PICKONE : + cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl", + getenv("LANG")); + break; + case PPD_UI_PICKMANY : + cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickmany.tmpl", + getenv("LANG")); + break; + } + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "option-trailer.tmpl", + getenv("LANG")); + } + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) != NULL) + { + /* + * Add the job sheets options... + */ + + cgiSetVariable("GROUP", "Banners"); + cgiCopyTemplateLang(stdout, TEMPLATES, "option-header.tmpl", + getenv("LANG")); + + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); + for (k = 0; k < attr->num_values; k ++) + { + cgiSetArray("CHOICES", k, attr->values[k].string.text); + cgiSetArray("TEXT", k, attr->values[k].string.text); + } + + attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); + + cgiSetVariable("KEYWORD", "job_sheets_start"); + cgiSetVariable("KEYTEXT", "Starting Banner"); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); + + cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl", + getenv("LANG")); + + cgiSetVariable("KEYWORD", "job_sheets_end"); + cgiSetVariable("KEYTEXT", "Ending Banner"); + cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ? + "" : attr->values[1].string.text); + + cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl", + getenv("LANG")); + + cgiCopyTemplateLang(stdout, TEMPLATES, "option-trailer.tmpl", + getenv("LANG")); + } + + ippDelete(response); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "config-printer2.tmpl", + getenv("LANG")); + } + else + { + /* + * Set default options... + */ + + outfd = cupsTempFd(tempfile, sizeof(tempfile)); + in = fopen(filename, "rb"); + out = fdopen(outfd, "wb"); + + if (outfd < 0 || in == NULL || out == NULL) + { + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + unlink(filename); + return; + } + + while (get_line(line, sizeof(line), in) != NULL) + { + if (strncmp(line, "*Default", 8) != 0) + fprintf(out, "%s\n", line); + else + { + /* + * Get default option name... + */ + + strncpy(keyword, line + 8, sizeof(keyword) - 1); + keyword[sizeof(keyword) - 1] = '\0'; + + for (keyptr = keyword; *keyptr; keyptr ++) + if (*keyptr == ':' || isspace(*keyptr)) + break; + + *keyptr = '\0'; + + if (strcmp(keyword, "PageRegion") == 0) + var = cgiGetVariable("PageSize"); + else + var = cgiGetVariable(keyword); + + if (var != NULL) + fprintf(out, "*Default%s: %s\n", keyword, var); + else + fprintf(out, "%s\n", line); + } + } + + fclose(in); + fclose(out); + close(outfd); + + /* + * Build a CUPS_ADD_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * job-sheets-default + * [ppd file] + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_ADD_PRINTER; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-default", 2, NULL, NULL); + attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start")); + attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end")); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoFileRequest(http, request, "/admin/", tempfile)) != NULL) + { + status = response->request.status.status_code; + ippDelete(response); + } + else + status = IPP_NOT_AUTHORIZED; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-configured.tmpl", getenv("LANG")); + + unlink(tempfile); + } + + unlink(filename); +} + + +/* + * 'do_delete_class()' - Delete a class... + */ + +static void +do_delete_class(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *pclass; /* Printer class name */ + ipp_status_t status; /* Operation status... */ + + + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiCopyTemplateLang(stdout, TEMPLATES, "class-confirm.tmpl", getenv("LANG")); + return; + } + + if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + /* + * Build a CUPS_DELETE_CLASS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_DELETE_CLASS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else + cgiCopyTemplateLang(stdout, TEMPLATES, "class-deleted.tmpl", getenv("LANG")); +} + + +/* + * 'do_delete_printer()' - Delete a printer... + */ + +static void +do_delete_printer(http_t *http, /* I - HTTP connection */ + cups_lang_t *language)/* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *printer; /* Printer printer name */ + ipp_status_t status; /* Operation status... */ + + + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-confirm.tmpl", getenv("LANG")); + return; + } + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + /* + * Build a CUPS_DELETE_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_DELETE_PRINTER; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-deleted.tmpl", getenv("LANG")); +} + + +/* + * 'do_job_op()' - Do a job operation. + */ + +static void +do_job_op(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + ipp_op_t op) /* I - Operation to perform */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *job; /* Job ID */ + const char *printer; /* Printer name (purge-jobs) */ + ipp_status_t status; /* Operation status... */ + + + if ((job = cgiGetVariable("JOB_ID")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%s", job); + else if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + /* + * Build a job request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri or printer-uri (purge-jobs) + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = op; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (job) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, uri); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "root"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else if (op == IPP_CANCEL_JOB) + cgiCopyTemplateLang(stdout, TEMPLATES, "job-cancel.tmpl", getenv("LANG")); + else if (op == IPP_HOLD_JOB) + cgiCopyTemplateLang(stdout, TEMPLATES, "job-hold.tmpl", getenv("LANG")); + else if (op == IPP_RELEASE_JOB) + cgiCopyTemplateLang(stdout, TEMPLATES, "job-release.tmpl", getenv("LANG")); + else if (op == IPP_RESTART_JOB) + cgiCopyTemplateLang(stdout, TEMPLATES, "job-restart.tmpl", getenv("LANG")); +} + + +/* + * 'do_printer_op()' - Do a printer operation. + */ + +static void +do_printer_op(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + ipp_op_t op) /* I - Operation to perform */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer; /* Printer name (purge-jobs) */ + ipp_status_t status; /* Operation status... */ + + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + return; + } + + /* + * Build a printer request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = op; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else if (op == IPP_PAUSE_PRINTER) + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-stop.tmpl", getenv("LANG")); + else if (op == IPP_RESUME_PRINTER) + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-start.tmpl", getenv("LANG")); + else if (op == CUPS_ACCEPT_JOBS) + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-accept.tmpl", getenv("LANG")); + else if (op == CUPS_REJECT_JOBS) + cgiCopyTemplateLang(stdout, TEMPLATES, "printer-reject.tmpl", getenv("LANG")); +} + + +/* + * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF. + */ + +static char * /* O - Pointer to buf or NULL on EOF */ +get_line(char *buf, /* I - Line buffer */ + int length, /* I - Length of buffer */ + FILE *fp) /* I - File to read from */ +{ + char *bufptr; /* Pointer into buffer */ + int ch; /* Character from file */ + + + length --; + bufptr = buf; + + while ((ch = getc(fp)) != EOF) + { + if (ch == '\n') + break; + else if (ch == '\r') + { + /* + * Look for LF... + */ + + ch = getc(fp); + if (ch != '\n' && ch != EOF) + ungetc(ch, fp); + + break; + } + + *bufptr++ = ch; + length --; + if (length == 0) + break; + } + + *bufptr = '\0'; + + if (ch == EOF) + return (NULL); + else + return (buf); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h new file mode 100644 index 0000000000..405371f1c8 --- /dev/null +++ b/cgi-bin/cgi.h @@ -0,0 +1,87 @@ +/* + * "$Id$" + * + * CGI support library definitions. + * + * Copyright 1997-2001 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _CGI_H_ +# define _CGI_H_ + +# include +# include +# include +# include + +# ifdef WIN32 +# include +# include +# include +# define strcasecmp(s,t) stricmp((s),(t)) +# define strncasecmp(s,t,n) strnicmp((s),(t),(n)) +# else +# include +# endif /* WIN32 */ + + +/* + * Prototypes... + */ + +extern int cgiInitialize(void); +extern void cgiAbort(const char *title, const char *stylesheet, + const char *format, ...); +extern int cgiCheckVariables(const char *names); +extern const char *cgiGetArray(const char *name, int element); +extern int cgiGetSize(const char *name); +extern void cgiSetSize(const char *name, int size); +extern const char *cgiGetVariable(const char *name); +extern void cgiSetArray(const char *name, int element, + const char *value); +extern void cgiSetVariable(const char *name, const char *value); +extern void cgiCopyTemplateFile(FILE *out, const char *tmpl); +extern void cgiCopyTemplateLang(FILE *out, const char *directory, + const char *tmpl, const char *lang); + +extern void cgiStartHTML(FILE *out, const char *author, + const char *stylesheet, + const char *keywords, + const char *description, + const char *title, ...); +extern void cgiEndHTML(FILE *out); + +extern FILE *cgiEMailOpen(const char *from, const char *to, + const char *cc, const char *subject, + int multipart); +extern void cgiEMailPart(FILE *mail, const char *type, + const char *charset, const char *encoding); +extern void cgiEMailClose(FILE *mail); + +extern char *cgiGetCookie(const char *name, char *buf, int buflen); +extern void cgiSetCookie(const char *name, const char *value, + const char *path, const char *domain, + time_t expires, int secure); + +# define cgiGetUser() getenv("REMOTE_USER") +# define cgiGetHost() (getenv("REMOTE_HOST") == NULL ? getenv("REMOTE_ADDR") : getenv("REMOTE_HOST")) + +#endif /* !_CGI_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c new file mode 100644 index 0000000000..9138678c2b --- /dev/null +++ b/cgi-bin/classes.c @@ -0,0 +1,360 @@ +/* + * "$Id$" + * + * Class status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + char *pclass; /* Printer class name */ + http_t *http; /* Connection to the server */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + ipp_status_t status; /* Operation status... */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + const char *which_jobs; /* Which jobs to show */ + const char *op; /* Operation to perform, if any */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + op = cgiGetVariable("OP"); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + /* + * See if we need to show a list of printers or the status of a + * single printer... + */ + + ippSetServerVersion(); + + pclass = argv[0]; + if (strcmp(pclass, "/") == 0 || strcmp(pclass, "classes.cgi") == 0) + { + pclass = NULL; + cgiSetVariable("TITLE", cupsLangString(language, CUPS_MSG_CLASS)); + } + else + cgiSetVariable("TITLE", pclass); + + cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG")); + + if (op == NULL || strcasecmp(op, "print-test-page") != 0) + { + /* + * Get the default destination... + */ + + request = ippNew(); + request->request.op.operation_id = CUPS_GET_DEFAULT; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + cgiSetVariable("DEFAULT_NAME", attr->values[0].string.text); + + if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) + { + char method[HTTP_MAX_URI], + username[HTTP_MAX_URI], + hostname[HTTP_MAX_URI], + resource[HTTP_MAX_URI], + uri[HTTP_MAX_URI]; + int port; /* URI data */ + const char *server; /* Name of server */ + + + /* + * Map localhost access to localhost... + */ + + server = getenv("SERVER_NAME"); + + httpSeparate(attr->values[0].string.text, method, username, + hostname, &port, resource); + + if (strcasecmp(hostname, server) == 0 && + (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 || + strcmp(getenv("REMOTE_HOST"), "localhost") == 0 || + strcmp(getenv("REMOTE_HOST"), server) == 0)) + strcpy(hostname, "localhost"); + + /* + * Rewrite URI with HTTP address... + */ + + snprintf(uri, sizeof(uri), "http://%s:%d%s", hostname, port, + resource); + + cgiSetVariable("DEFAULT_URI", uri); + } + + ippDelete(response); + } + + /* + * Get the class info... + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (pclass == NULL) + { + /* + * Build a CUPS_GET_CLASSES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request->request.op.operation_id = CUPS_GET_CLASSES; + request->request.op.request_id = 1; + } + else + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/classes/%s", getenv("SERVER_NAME"), + pclass); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + } + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + } + + /* + * Write the report... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "classes.tmpl", getenv("LANG")); + + /* + * Get jobs for the specified class if a class has been chosen... + */ + + if (pclass != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/classes/%s", getenv("SERVER_NAME"), + pclass); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + + cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG")); + } + } + } + else + { + /* + * Print a test page... + */ + + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass); + + /* + * Build an IPP_PRINT_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + * document-format + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "root"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", + NULL, "Test Page"); + + ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/postscript"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoFileRequest(http, request, uri + 15, + CUPS_DATADIR "/data/testprint.ps")) != NULL) + { + status = response->request.status.status_code; + ippSetCGIVars(response, NULL, NULL); + + ippDelete(response); + } + else + status = IPP_GONE; + + cgiSetVariable("PRINTER_NAME", pclass); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else + cgiCopyTemplateLang(stdout, TEMPLATES, "test-page.tmpl", getenv("LANG")); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG")); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/html.c b/cgi-bin/html.c new file mode 100644 index 0000000000..77c011cf3a --- /dev/null +++ b/cgi-bin/html.c @@ -0,0 +1,89 @@ +/* + * "$Id$" + * + * CGI HTML functions. + * + * Copyright 1997-2001 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiStartHTML() - Start an HTML document stream. + * cgiEndHTML() - End an HTML document stream. + */ + +#include "cgi.h" +#include + + +/* + * 'cgiStartHTML()' - Start an HTML document stream. + */ + +void +cgiStartHTML(FILE *out, /* I - Output file to use */ + const char *stylesheet, /* I - Stylesheet to use */ + const char *author, /* I - Author name */ + const char *keywords, /* I - Search keywords */ + const char *description, /* I - Description of document */ + const char *title, /* I - Title for page */ + ...) /* I - Any addition args for title */ +{ + va_list ap; /* Argument pointer */ + + + fputs("Content-type: text/html\n\n", out); + fputs("\n", out); + fputs("\n", out); + fputs("\n", out); + + fputs("\t\n", out); + va_start(ap, title); + vfprintf(out, title, ap); + va_end(ap); + fputs("\n", out); + + if (stylesheet) + fprintf(out, "\t\n", + stylesheet); + if (author) + fprintf(out, "\t\n", author); + if (keywords) + fprintf(out, "\t\n", keywords); + if (description) + fprintf(out, "\t\n", description); + + fputs("\n", out); + fputs("\n", out); +} + + +/* + * 'cgiEndHTML()' - End an HTML document stream. + */ + +void +cgiEndHTML(FILE *out) /* I - Output file to use */ +{ + fputs("\n", out); + fputs("\n", out); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c new file mode 100644 index 0000000000..6cc1448ef3 --- /dev/null +++ b/cgi-bin/ipp-var.c @@ -0,0 +1,299 @@ +/* + * "$Id$" + * + * IPP variable routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ippGetTemplateDir() - Get the templates directory... + * ippSetServerVersion() - Set the server name and CUPS version... + * ippSetCGIVars() - Set CGI variables from an IPP response. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * 'ippGetTemplateDir()' - Get the templates directory... + */ + +char * /* O - Template directory */ +ippGetTemplateDir(void) +{ + const char *datadir; /* CUPS_DATADIR env var */ + static char templates[1024] = ""; /* Template directory */ + + + if (!templates[0]) + { + /* + * Build the template directory pathname... + */ + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(templates, sizeof(templates), "%s/templates", datadir); + } + + return (templates); +} + + +/* + * 'ippSetServerVersion()' - Set the server name and CUPS version... + */ + +void +ippSetServerVersion(void) +{ + cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); + cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); + cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); +} + + +/* + * 'ippSetCGIVars()' - Set CGI variables from an IPP response. + */ + +void +ippSetCGIVars(ipp_t *response, /* I - Response data to be copied... */ + const char *filter_name, /* I - Filter name */ + const char *filter_value) /* I - Filter value */ +{ + int element; /* Element in CGI array */ + ipp_attribute_t *attr, /* Attribute in response... */ + *filter; /* Filtering attribute */ + int i; /* Looping var */ + char name[1024], /* Name of attribute */ + value[16384], /* Value(s) */ + *valptr; /* Pointer into value */ + char method[HTTP_MAX_URI], + username[HTTP_MAX_URI], + hostname[HTTP_MAX_URI], + resource[HTTP_MAX_URI], + uri[HTTP_MAX_URI]; + int port; /* URI data */ + int ishttps; /* Using encryption? */ + const char *server; /* Name of server */ + struct tm *date; /* Date information */ + + + ippSetServerVersion(); + + server = getenv("SERVER_NAME"); + ishttps = getenv("HTTPS") != NULL; + + for (attr = response->attrs; + attr && attr->group_tag == IPP_TAG_OPERATION; + attr = attr->next); + + for (element = 0; attr != NULL; attr = attr->next, element ++) + { + /* + * Copy attributes to a separator... + */ + + if (filter_name) + { + for (filter = attr; + filter != NULL && filter->group_tag != IPP_TAG_ZERO; + filter = filter->next) + if (filter->name && strcmp(filter->name, filter_name) == 0 && + (filter->value_tag == IPP_TAG_STRING || + (filter->value_tag >= IPP_TAG_TEXTLANG && + filter->value_tag <= IPP_TAG_MIMETYPE)) && + filter->values[0].string.text != NULL && + strcasecmp(filter->values[0].string.text, filter_value) == 0) + break; + + if (!filter) + return; + + if (filter->group_tag == IPP_TAG_ZERO) + { + attr = filter; + element --; + continue; + } + } + + for (; attr != NULL && attr->group_tag != IPP_TAG_ZERO; attr = attr->next) + { + /* + * Copy the attribute name, substituting "_" for "-"... + */ + + if (attr->name == NULL) + continue; + + for (i = 0; attr->name[i]; i ++) + if (attr->name[i] == '-') + name[i] = '_'; + else + name[i] = attr->name[i]; + + name[i] = '\0'; + + /* + * Add "job_printer_name" variable if we have a "job_printer_uri" + * attribute... + */ + + if (strcmp(name, "job_printer_uri") == 0) + { + if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL) + valptr = "unknown"; + else + valptr ++; + + cgiSetArray("job_printer_name", element, valptr); + } + + /* + * Copy values... + */ + + value[0] = '\0'; /* Initially an empty string */ + value[sizeof(value) - 1] = '\0'; /* In case string gets full */ + valptr = value; /* Start at the beginning */ + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + strncat(valptr, ",", sizeof(value) - (valptr - value) - 1); + + valptr += strlen(valptr); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (strncmp(name, "time_at_", 8) == 0) + { + date = localtime((time_t *)&(attr->values[i].integer)); + strftime(valptr, sizeof(value) - (valptr - value), + CUPS_STRFTIME_FORMAT, date); + } + else + snprintf(valptr, sizeof(value) - (valptr - value), + "%d", attr->values[i].integer); + break; + + case IPP_TAG_BOOLEAN : + snprintf(valptr, sizeof(value) - (valptr - value), + "%d", attr->values[i].boolean); + break; + + case IPP_TAG_NOVALUE : + strncat(valptr, "novalue", sizeof(value) - (valptr - value) - 1); + break; + + case IPP_TAG_RANGE : + snprintf(valptr, sizeof(value) - (valptr - value), + "%d-%d", attr->values[i].range.lower, + attr->values[i].range.upper); + break; + + case IPP_TAG_RESOLUTION : + snprintf(valptr, sizeof(value) - (valptr - value), + "%dx%d%s", attr->values[i].resolution.xres, + attr->values[i].resolution.yres, + attr->values[i].resolution.units == IPP_RES_PER_INCH ? + "dpi" : "dpc"); + break; + + case IPP_TAG_URI : + if (strchr(attr->values[i].string.text, ':') != NULL) + { + httpSeparate(attr->values[i].string.text, method, username, + hostname, &port, resource); + + if (strcmp(method, "ipp") == 0 || + strcmp(method, "http") == 0) + { + /* + * Map localhost access to localhost and local port... + */ + + if (strcasecmp(hostname, server) == 0 && + (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 || + strcmp(getenv("REMOTE_HOST"), "localhost") == 0 || + strcmp(getenv("REMOTE_HOST"), server) == 0)) + { + strcpy(hostname, "localhost"); + port = atoi(getenv("SERVER_PORT")); + } + + /* + * Rewrite URI with HTTP address... + */ + + if (username[0]) + snprintf(uri, sizeof(uri), "%s://%s@%s:%d%s", + ishttps ? "https" : "http", + username, hostname, port, resource); + else + snprintf(uri, sizeof(uri), "%s://%s:%d%s", + ishttps ? "https" : "http", + hostname, port, resource); + + strncat(valptr, uri, sizeof(value) - (valptr - value) - 1); + break; + } + } + + case IPP_TAG_STRING : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + strncat(valptr, attr->values[i].string.text, + sizeof(value) - (valptr - value) - 1); + break; + + default : + break; /* anti-compiler-warning-code */ + } + } + + /* + * Add the element... + */ + + cgiSetArray(name, element, value); + } + + if (attr == NULL) + break; + } +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/ipp-var.h b/cgi-bin/ipp-var.h new file mode 100644 index 0000000000..f116794335 --- /dev/null +++ b/cgi-bin/ipp-var.h @@ -0,0 +1,55 @@ +/* + * "$Id$" + * + * IPP variable definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include "cgi.h" + + +/* + * Definitions... + */ + +#define TEMPLATES ippGetTemplateDir() + + +/* + * Prototype... + */ + +extern char *ippGetTemplateDir(void); +extern void ippSetServerVersion(void); +extern void ippSetCGIVars(ipp_t *, const char *, const char *); + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c new file mode 100644 index 0000000000..f630c9445f --- /dev/null +++ b/cgi-bin/jobs.c @@ -0,0 +1,139 @@ +/* + * "$Id$" + * + * Job status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + http_t *http; /* Connection to the server */ + const char *which_jobs; /* Which jobs to show */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + cgiSetVariable("TITLE", "Jobs"); + + ippSetServerVersion(); + + cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG")); + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, + "ipp://localhost/jobs"); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + + cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG")); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG")); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c new file mode 100644 index 0000000000..f49a86e0b9 --- /dev/null +++ b/cgi-bin/printers.c @@ -0,0 +1,360 @@ +/* + * "$Id$" + * + * Printer status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + char *printer; /* Printer name */ + http_t *http; /* Connection to the server */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + ipp_status_t status; /* Operation status... */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + const char *which_jobs; /* Which jobs to show */ + const char *op; /* Operation to perform, if any */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + op = cgiGetVariable("OP"); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + /* + * See if we need to show a list of printers or the status of a + * single printer... + */ + + ippSetServerVersion(); + + printer = argv[0]; + if (strcmp(printer, "/") == 0 || strcmp(printer, "printers.cgi") == 0) + { + printer = NULL; + cgiSetVariable("TITLE", cupsLangString(language, CUPS_MSG_PRINTER)); + } + else + cgiSetVariable("TITLE", printer); + + cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG")); + + if (op == NULL || strcasecmp(op, "print-test-page") != 0) + { + /* + * Get the default destination... + */ + + request = ippNew(); + request->request.op.operation_id = CUPS_GET_DEFAULT; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + cgiSetVariable("DEFAULT_NAME", attr->values[0].string.text); + + if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) + { + char method[HTTP_MAX_URI], + username[HTTP_MAX_URI], + hostname[HTTP_MAX_URI], + resource[HTTP_MAX_URI], + uri[HTTP_MAX_URI]; + int port; /* URI data */ + const char *server; /* Name of server */ + + + /* + * Map localhost access to localhost... + */ + + server = getenv("SERVER_NAME"); + + httpSeparate(attr->values[0].string.text, method, username, + hostname, &port, resource); + + if (strcasecmp(hostname, server) == 0 && + (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 || + strcmp(getenv("REMOTE_HOST"), "localhost") == 0 || + strcmp(getenv("REMOTE_HOST"), server) == 0)) + strcpy(hostname, "localhost"); + + /* + * Rewrite URI with HTTP address... + */ + + snprintf(uri, sizeof(uri), "http://%s:%d%s", hostname, port, + resource); + + cgiSetVariable("DEFAULT_URI", uri); + } + + ippDelete(response); + } + + /* + * Get the printer info... + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (printer == NULL) + { + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + } + else + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/printers/%s", getenv("SERVER_NAME"), + printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + } + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + } + + /* + * Write the report... + */ + + cgiCopyTemplateLang(stdout, TEMPLATES, "printers.tmpl", getenv("LANG")); + + /* + * Get jobs for the specified printer if a printer has been chosen... + */ + + if (printer != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/printers/%s", getenv("SERVER_NAME"), + printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response, NULL, NULL); + ippDelete(response); + + cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG")); + } + } + } + else + { + /* + * Print a test page... + */ + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + + /* + * Build an IPP_PRINT_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + * document-format + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "root"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", + NULL, "Test Page"); + + ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/postscript"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoFileRequest(http, request, uri + 15, + CUPS_DATADIR "/data/testprint.ps")) != NULL) + { + status = response->request.status.status_code; + ippSetCGIVars(response, NULL, NULL); + + ippDelete(response); + } + else + status = IPP_GONE; + + cgiSetVariable("PRINTER_NAME", printer); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG")); + } + else + cgiCopyTemplateLang(stdout, TEMPLATES, "test-page.tmpl", getenv("LANG")); + } + + cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG")); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/template.c b/cgi-bin/template.c new file mode 100644 index 0000000000..32cc03ecea --- /dev/null +++ b/cgi-bin/template.c @@ -0,0 +1,499 @@ +/* + * "$Id$" + * + * CGI template function. + * + * Copyright 1997-2001 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiCopyTemplateFile() - Copy a template file and replace all the + * '{variable}' strings with the variable value. + * cgiCopyTemplateLang() - Copy a template file using a language... + * cgi_copy() - Copy the template file, substituting as needed... + * cgi_puts() - Put a string to the output file, quoting as + * needed... + */ + +#include "cgi.h" + + +/* + * Local functions... + */ + +static void cgi_copy(FILE *out, FILE *in, int element, char term); +static void cgi_puts(const char *s, FILE *out); + + +/* + * 'cgiCopyTemplateFile()' - Copy a template file and replace all the + * '{variable}' strings with the variable value. + */ + +void +cgiCopyTemplateFile(FILE *out, /* I - Output file */ + const char *tmpl) /* I - Template file to read */ +{ + FILE *in; /* Input file */ + + + /* + * Open the template file... + */ + + if ((in = fopen(tmpl, "r")) == NULL) + return; + + /* + * Parse the file to the end... + */ + + cgi_copy(out, in, 0, 0); + + /* + * Close the template file and return... + */ + + fclose(in); +} + + +/* + * 'cgiCopyTemplateLang()' - Copy a template file using a language... + */ + +void +cgiCopyTemplateLang(FILE *out, /* I - Output file */ + const char *directory, /* I - Directory */ + const char *tmpl, /* I - Base filename */ + const char *lang) /* I - Language */ +{ + int i; /* Looping var */ + char filename[1024], /* Filename */ + locale[16]; /* Locale name */ + FILE *in; /* Input file */ + + + /* + * Convert the language to a locale name... + */ + + if (lang != NULL) + { + for (i = 0; lang[i] && i < 15; i ++) + if (isalnum(lang[i])) + locale[i] = tolower(lang[i]); + else + locale[i] = '_'; + + locale[i] = '\0'; + } + else + locale[0] = '\0'; + + /* + * See if we have a template file for this language... + */ + + snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl); + if (access(filename, 0)) + { + locale[2] = '\0'; + + snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl); + if (access(filename, 0)) + snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl); + } + + /* + * Open the template file... + */ + + if ((in = fopen(filename, "r")) == NULL) + return; + + /* + * Parse the file to the end... + */ + + cgi_copy(out, in, 0, 0); + + /* + * Close the template file and return... + */ + + fclose(in); +} + + +/* + * 'cgi_copy()' - Copy the template file, substituting as needed... + */ + +static void +cgi_copy(FILE *out, /* I - Output file */ + FILE *in, /* I - Input file */ + int element, /* I - Element number (0 to N) */ + char term) /* I - Terminating character */ +{ + int ch; /* Character from file */ + char op; /* Operation */ + char name[255], /* Name of variable */ + *nameptr, /* Pointer into name */ + innername[255], /* Inner comparison name */ + *innerptr, /* Pointer into inner name */ + *s; /* String pointer */ + const char *value; /* Value of variable */ + const char *innerval; /* Inner value */ + const char *outptr; /* Output string pointer */ + char outval[1024], /* Formatted output string */ + compare[1024]; /* Comparison string */ + int result; /* Result of comparison */ + + + /* + * Parse the file to the end... + */ + + while ((ch = getc(in)) != EOF) + if (ch == term) + break; + else if (ch == '{') + { + /* + * Get a variable name... + */ + + for (s = name; (ch = getc(in)) != EOF;) + if (strchr("}]<>=! \t\n", ch)) + break; + else if (s > name && ch == '?') + break; + else if (s < (name + sizeof(name) - 1)) + *s++ = ch; + + *s = '\0'; + + if (s == name && isspace(ch)) + { + if (out) + { + putc('{', out); + putc(ch, out); + } + + continue; + } + + /* + * See if it has a value... + */ + + if (name[0] == '?') + { + /* + * Insert value only if it exists... + */ + + if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1])) + { + *nameptr++ = '\0'; + + if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL) + outptr = value; + else + { + outval[0] = '\0'; + outptr = outval; + } + } + if ((value = cgiGetArray(name + 1, element)) != NULL) + outptr = value; + else + { + outval[0] = '\0'; + outptr = outval; + } + } + else if (name[0] == '#') + { + /* + * Insert count... + */ + + if (name[1]) + sprintf(outval, "%d", cgiGetSize(name + 1)); + else + sprintf(outval, "%d", element + 1); + + outptr = outval; + } + else if (name[0] == '[') + { + /* + * Loop for # of elements... + */ + + int i; /* Looping var */ + long pos; /* File position */ + int count; /* Number of elements */ + + + if (isdigit(name[1])) + count = atoi(name + 1); + else + count = cgiGetSize(name + 1); + + pos = ftell(in); + + if (count > 0) + { + for (i = 0; i < count; i ++) + { + fseek(in, pos, SEEK_SET); + cgi_copy(out, in, i, '}'); + } + } + else + cgi_copy(NULL, in, 0, '}'); + + continue; + } + else + { + /* + * Insert variable or variable name (if element is NULL)... + */ + + if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1])) + { + *nameptr++ = '\0'; + if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL) + { + snprintf(outval, sizeof(outval), "{%s}", name); + outptr = outval; + } + else + outptr = value; + } + else if ((value = cgiGetArray(name, element)) == NULL) + { + snprintf(outval, sizeof(outval), "{%s}", name); + outptr = outval; + } + else + outptr = value; + } + + /* + * See if the terminating character requires another test... + */ + + if (ch == '}') + { + /* + * End of substitution... + */ + + if (out) + cgi_puts(outptr, out); + + continue; + } + + /* + * OK, process one of the following checks: + * + * {name?exist:not-exist} Exists? + * {name=value?true:false} Equal + * {namevalue?true:false} Greater than + * {name!value?true:false} Not equal + */ + + if (ch == '?') + { + /* + * Test for existance... + */ + + result = cgiGetArray(name, element) != NULL && outval[0]; + } + else + { + /* + * Compare to a string... + */ + + op = ch; + + for (s = compare; (ch = getc(in)) != EOF;) + if (ch == '?') + break; + else if (s >= (compare + sizeof(compare) - 1)) + continue; + else if (ch == '#') + { + sprintf(s, "%d", element + 1); + s += strlen(s); + } + else if (ch == '{') + { + /* + * Grab the value of a variable... + */ + + innerptr = innername; + while ((ch = getc(in)) != EOF && ch != '}') + if (innerptr < (innername + sizeof(innername) - 1)) + *innerptr++ = ch; + *innerptr = '\0'; + + if (innername[0] == '#') + sprintf(s, "%d", cgiGetSize(innername + 1)); + else if ((innerptr = strrchr(innername, '-')) != NULL && + isdigit(innerptr[1])) + { + *innerptr++ = '\0'; + if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL) + *s = '\0'; + else + { + strncpy(s, innerval, sizeof(compare) - (s - compare) - 1); + compare[sizeof(compare) - 1] = '\0'; + } + } + else if (innername[0] == '?') + { + if ((innerval = cgiGetArray(innername + 1, element)) == NULL) + *s = '\0'; + else + { + strncpy(s, innerval, sizeof(compare) - (s - compare) - 1); + compare[sizeof(compare) - 1] = '\0'; + } + } + else if ((innerval = cgiGetArray(innername, element)) == NULL) + snprintf(s, sizeof(s), "{%s}", innername); + else + { + strncpy(s, innerval, sizeof(compare) - (s - compare) - 1); + compare[sizeof(compare) - 1] = '\0'; + } + + s += strlen(s); + } + else if (ch == '\\') + *s++ = getc(in); + else + *s++ = ch; + + *s = '\0'; + + if (ch != '?') + return; + + /* + * Do the comparison... + */ + + switch (op) + { + case '<' : + result = strcasecmp(outptr, compare) < 0; + break; + case '>' : + result = strcasecmp(outptr, compare) > 0; + break; + case '=' : + result = strcasecmp(outptr, compare) == 0; + break; + case '!' : + result = strcasecmp(outptr, compare) != 0; + break; + default : + result = 1; + break; + } + } + + if (result) + { + /* + * Comparison true; output first part and ignore second... + */ + + cgi_copy(out, in, element, ':'); + cgi_copy(NULL, in, element, '}'); + } + else + { + /* + * Comparison false; ignore first part and output second... + */ + + cgi_copy(NULL, in, element, ':'); + cgi_copy(out, in, element, '}'); + } + } + else if (ch == '\\') /* Quoted char */ + { + if (out) + putc(getc(in), out); + else + getc(in); + } + else if (out) + putc(ch, out); + + /* + * Flush any pending output... + */ + + if (out) + fflush(out); +} + + +/* + * 'cgi_puts()' - Put a string to the output file, quoting as needed... + */ + +static void +cgi_puts(const char *s, + FILE *out) +{ + while (*s) + { + if (s[0] == '<' && s[1] != '/' && !isalpha(s[1])) + fputs("<", out); + else if (*s == '\"') + fputs(""", out); + else if (s[0] == '&' && isspace(s[1])) + fputs("&", out); + else + putc(*s, out); + + s ++; + } +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/var.c b/cgi-bin/var.c new file mode 100644 index 0000000000..a9d947acd8 --- /dev/null +++ b/cgi-bin/var.c @@ -0,0 +1,672 @@ +/* + * "$Id$" + * + * CGI form variable and array functions. + * + * Copyright 1997-2001 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiInitialize() - Initialize the CGI variable "database"... + * cgiCheckVariables() - Check for the presence of "required" variables. + * cgiGetArray() - Get an element from a form array... + * cgiGetSize() - Get the size of a form array value. + * cgiGetVariable() - Get a CGI variable from the database... + * cgiSetArray() - Set array element N to the specified string. + * cgiSetVariable() - Set a CGI variable in the database... + * cgi_add_variable() - Add a form variable. + * cgi_compare_variables() - Compare two variables. + * cgi_find_variable() - Find a variable... + * cgi_initialize_get() - Initialize form variables using the GET method. + * cgi_initialize_post() - Initialize variables using the POST method. + * cgi_initialize_string() - Initialize form variables from a string. + * cgi_sort_variables() - Sort all form variables for faster lookup. + */ + +/*#define DEBUG*/ +#include "cgi.h" +#include +#include + + +/* + * Data structure to hold all the CGI form variables and arrays... + */ + +typedef struct +{ + const char *name; /* Name of variable */ + int nvalues, /* Number of values */ + avalues; /* Number of values allocated */ + const char **values; /* Value(s) of variable */ +} var_t; + + +/* + * Local globals... + */ + +static int form_count = 0, /* Form variable count */ + form_alloc = 0; /* Number of variables allocated */ +static var_t *form_vars = NULL; /* Form variables */ + + +/* + * Local functions... + */ + +static void cgi_add_variable(const char *name, int element, + const char *value); +static int cgi_compare_variables(const var_t *v1, const var_t *v2); +static var_t *cgi_find_variable(const char *name); +static int cgi_initialize_get(void); +static int cgi_initialize_post(void); +static int cgi_initialize_string(const char *data); +static void cgi_sort_variables(void); + + +/* + * 'cgiInitialize()' - Initialize the CGI variable "database"... + */ + +int /* O - Non-zero if there was form data */ +cgiInitialize(void) +{ + char *method; /* Form posting method */ + + +#ifdef DEBUG + setbuf(stdout, NULL); + puts("Content-type: text/plain\n"); +#endif /* DEBUG */ + + method = getenv("REQUEST_METHOD"); + + if (method == NULL) + return (0); + + if (strcasecmp(method, "GET") == 0) + return (cgi_initialize_get()); + else if (strcasecmp(method, "POST") == 0) + return (cgi_initialize_post()); + else + return (0); +} + + +/* + * 'cgiCheckVariables()' - Check for the presence of "required" variables. + * + * Names may be separated by spaces and/or commas. + */ + +int /* O - 1 if all variables present, 0 otherwise */ +cgiCheckVariables(const char *names) /* I - Variables to look for */ +{ + char name[255], /* Current variable name */ + *s; /* Pointer in string */ + const char *val; /* Value of variable */ + int element; /* Array element number */ + + + if (names == NULL) + return (1); + + while (*names != '\0') + { + while (*names == ' ' || *names == ',') + names ++; + + for (s = name; *names != '\0' && *names != ' ' && *names != ','; s ++, names ++) + *s = *names; + + *s = 0; + if (name[0] == '\0') + break; + + if ((s = strrchr(name, '-')) != NULL) + { + *s = '\0'; + element = atoi(s + 1) - 1; + val = cgiGetArray(name, element); + } + else + val = cgiGetVariable(name); + + if (val == NULL) + return (0); + + if (*val == '\0') + return (0); /* Can't be blank, either! */ + } + + return (1); +} + + +/* + * 'cgiGetArray()' - Get an element from a form array... + */ + +const char * /* O - Element value or NULL */ +cgiGetArray(const char *name, /* I - Name of array variable */ + int element) /* I - Element number (0 to N) */ +{ + var_t *var; /* Pointer to variable */ + + + if ((var = cgi_find_variable(name)) == NULL) + return (NULL); + + if (var->nvalues == 1) + return (var->values[0]); + + if (element < 0 || element >= var->nvalues) + return (NULL); + + return (var->values[element]); +} + + +/* + * 'cgiGetSize()' - Get the size of a form array value. + */ + +int /* O - Number of elements */ +cgiGetSize(const char *name) /* I - Name of variable */ +{ + var_t *var; /* Pointer to variable */ + + + if ((var = cgi_find_variable(name)) == NULL) + return (0); + + return (var->nvalues); +} + + +/* + * 'cgiGetVariable()' - Get a CGI variable from the database... + * + * Returns NULL if the variable doesn't exist... If the variable is an + * array of values, returns the last element... + */ + +const char * /* O - Value of variable */ +cgiGetVariable(const char *name)/* I - Name of variable */ +{ + const var_t *var; /* Returned variable */ + + + var = cgi_find_variable(name); + +#ifdef DEBUG + if (var == NULL) + printf("cgiGetVariable(\"%s\") is returning NULL...\n", name); + else + printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name, + var->values[var->nvalues - 1]); +#endif /* DEBUG */ + + return ((var == NULL) ? NULL : var->values[var->nvalues - 1]); +} + + +/* + * 'cgiSetArray()' - Set array element N to the specified string. + * + * If the variable array is smaller than (element + 1), the intervening + * elements are set to NULL. + */ + +void +cgiSetArray(const char *name, /* I - Name of variable */ + int element, /* I - Element number (0 to N) */ + const char *value) /* I - Value of variable */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || value == NULL || element < 0) + return; + + if ((var = cgi_find_variable(name)) == NULL) + { + cgi_add_variable(name, element, value); + cgi_sort_variables(); + } + else + { + if (element >= var->avalues) + { + var->avalues = element + 16; + var->values = (const char **)realloc((void *)(var->values), + sizeof(char *) * var->avalues); + } + + if (element >= var->nvalues) + { + for (i = var->nvalues; i < element; i ++) + var->values[i] = NULL; + + var->nvalues = element + 1; + } + else if (var->values[element]) + free((char *)var->values[element]); + + var->values[element] = strdup(value); + } +} + + +/* + * 'cgiSetSize()' - Set the array size. + */ + +void +cgiSetSize(const char *name, /* I - Name of variable */ + int size) /* I - Number of elements (0 to N) */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || size < 0) + return; + + if ((var = cgi_find_variable(name)) == NULL) + return; + + if (size >= var->avalues) + { + var->avalues = size + 16; + var->values = (const char **)realloc((void *)(var->values), + sizeof(char *) * var->avalues); + } + + if (size > var->nvalues) + { + for (i = var->nvalues; i < size; i ++) + var->values[i] = NULL; + } + else if (size < var->nvalues) + { + for (i = size; i < var->nvalues; i ++) + if (var->values[i]) + free((void *)(var->values[i])); + } + + var->nvalues = size; +} + + +/* + * 'cgiSetVariable()' - Set a CGI variable in the database... + * + * If the variable is an array, this truncates the array to a single element. + */ + +void +cgiSetVariable(const char *name, /* I - Name of variable */ + const char *value) /* I - Value of variable */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || value == NULL) + return; + + if ((var = cgi_find_variable(name)) == NULL) + { + cgi_add_variable(name, 0, value); + cgi_sort_variables(); + } + else + { + for (i = 0; i < var->nvalues; i ++) + if (var->values[i]) + free((char *)var->values[i]); + + var->values[0] = strdup(value); + var->nvalues = 1; + } +} + + +/* + * 'cgi_add_variable()' - Add a form variable. + */ + +static void +cgi_add_variable(const char *name, /* I - Variable name */ + int element, /* I - Array element number */ + const char *value) /* I - Variable value */ +{ + var_t *var; /* New variable */ + + + if (name == NULL || value == NULL) + return; + +#ifdef DEBUG + printf("Adding variable \'%s\' with value \'%s\'...\n", name, value); +#endif /* DEBUG */ + + if (form_count >= form_alloc) + { + if (form_alloc == 0) + form_vars = malloc(sizeof(var_t) * 16); + else + form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(var_t)); + + form_alloc += 16; + } + + var = form_vars + form_count; + var->name = strdup(name); + var->nvalues = element + 1; + var->avalues = element + 1; + var->values = calloc(element + 1, sizeof(char *)); + var->values[element] = strdup(value); + + form_count ++; +} + + +/* + * 'cgi_compare_variables()' - Compare two variables. + */ + +static int /* O - Result of comparison */ +cgi_compare_variables(const var_t *v1, /* I - First variable */ + const var_t *v2) /* I - Second variable */ +{ + return (strcasecmp(v1->name, v2->name)); +} + + +/* + * 'cgi_find_variable()' - Find a variable... + */ + +static var_t * /* O - Variable pointer or NULL */ +cgi_find_variable(const char *name) /* I - Name of variable */ +{ + var_t key; /* Search key */ + + + if (form_count < 1 || name == NULL) + return (NULL); + + key.name = name; + + return ((var_t *)bsearch(&key, form_vars, form_count, sizeof(var_t), + (int (*)(const void *, const void *))cgi_compare_variables)); +} + + +/* + * 'cgi_initialize_get()' - Initialize form variables using the GET method. + */ + +static int /* O - 1 if form data read */ +cgi_initialize_get(void) +{ + char *data; /* Pointer to form data string */ + + +#ifdef DEBUG + puts("Initializing variables using GET method..."); +#endif /* DEBUG */ + + /* + * Check to see if there is anything for us to read... + */ + + data = getenv("QUERY_STRING"); + if (data == NULL || strlen(data) == 0) + return (0); + + /* + * Parse it out and return... + */ + + return (cgi_initialize_string(data)); +} + + +/* + * 'cgi_initialize_post()' - Initialize variables using the POST method. + */ + +static int /* O - 1 if form data was read */ +cgi_initialize_post(void) +{ + char *content_length, /* Length of input data (string) */ + *data; /* Pointer to form data string */ + int length, /* Length of input data */ + nbytes, /* Number of bytes read this read() */ + tbytes, /* Total number of bytes read */ + status; /* Return status */ + + +#ifdef DEBUG + puts("Initializing variables using POST method..."); +#endif /* DEBUG */ + + /* + * Check to see if there is anything for us to read... + */ + + content_length = getenv("CONTENT_LENGTH"); + if (content_length == NULL || atoi(content_length) <= 0) + return (0); + + /* + * Get the length of the input stream and allocate a buffer for it... + */ + + length = atoi(content_length); + data = malloc(length + 1); + + if (data == NULL) + return (0); + + /* + * Read the data into the buffer... + */ + + for (tbytes = 0; tbytes < length; tbytes += nbytes) + if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0) + if (errno != EAGAIN) + { + free(data); + return (0); + } + + data[length] = '\0'; + + /* + * Parse it out... + */ + + status = cgi_initialize_string(data); + + /* + * Free the data and return... + */ + + free(data); + + return (status); +} + + +/* + * 'cgi_initialize_string()' - Initialize form variables from a string. + */ + +static int +cgi_initialize_string(const char *data) /* I - Form data string */ +{ + int done; /* True if we're done reading a form variable */ + char *s, /* Pointer to current form string */ + ch, /* Temporary character */ + name[255], /* Name of form variable */ + value[65536]; /* Variable value... */ + + + /* + * Check input... + */ + + if (data == NULL) + return (0); + + /* + * Loop until we've read all the form data... + */ + + while (*data != '\0') + { + /* + * Get the variable name... + */ + + for (s = name; *data != '\0'; data ++) + if (*data == '=') + break; + else if (*data >= ' ' && s < (name + sizeof(name) - 1)) + *s++ = *data; + + *s = '\0'; + if (*data == '=') + data ++; + else + return (0); + + /* + * Read the variable value... + */ + + for (s = value, done = 0; !done && *data != '\0'; data ++) + switch (*data) + { + case '&' : /* End of data... */ + done = 1; + break; + + case '+' : /* Escaped space character */ + if (s < (value + sizeof(value) - 1)) + *s++ = ' '; + break; + + case '%' : /* Escaped control character */ + /* + * Read the hex code... + */ + + if (s < (value + sizeof(value) - 1)) + { + data ++; + ch = *data - '0'; + if (ch > 9) + ch -= 7; + *s = ch << 4; + + data ++; + ch = *data - '0'; + if (ch > 9) + ch -= 7; + *s++ |= ch; + } + else + data += 2; + break; + + default : /* Other characters come straight through */ + if (*data >= ' ' && s < (value + sizeof(value) - 1)) + *s++ = *data; + break; + } + + *s = '\0'; /* nul terminate the string */ + + /* + * Remove trailing whitespace... + */ + + if (s > value) + s --; + + while (s >= value && *s == ' ') + *s-- = '\0'; + + /* + * Add the string to the variable "database"... + */ + + if ((s = strrchr(name, '-')) != NULL && isdigit(s[1])) + { + *s++ = '\0'; + if (value[0]) + cgiSetArray(name, atoi(s) - 1, value); + } + else if (cgiGetVariable(name) != NULL) + cgiSetArray(name, cgiGetSize(name), value); + else + cgiSetVariable(name, value); + } + + return (1); +} + + +/* + * 'cgi_sort_variables()' - Sort all form variables for faster lookup. + */ + +static void +cgi_sort_variables(void) +{ +#ifdef DEBUG + int i; + + + puts("Sorting variables..."); +#endif /* DEBUG */ + + if (form_count < 2) + return; + + qsort(form_vars, form_count, sizeof(var_t), + (int (*)(const void *, const void *))cgi_compare_variables); + +#ifdef DEBUG + puts("Sorted variable list is:"); + for (i = 0; i < form_count; i ++) + printf("%d: %s (%d) = \"%s\" ...\n", i, form_vars[i].name, + form_vars[i].nvalues, form_vars[i].values[0]); +#endif /* DEBUG */ +} + + +/* + * End of "$Id$". + */ diff --git a/conf/Makefile b/conf/Makefile new file mode 100644 index 0000000000..2e8cc5058d --- /dev/null +++ b/conf/Makefile @@ -0,0 +1,73 @@ +# +# "$Id$" +# +# Configuration file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Config files... +# + +KEEP = classes.conf client.conf cupsd.conf printers.conf +REPLACE = mime.convs mime.types + + +# +# Make everything... +# + +all: + + +# +# Clean all config and object files... +# + +clean: + + +# +# Install files... +# + +install: + -$(MKDIR) $(SERVERROOT) + $(CHMOD) ugo+rx $(SERVERROOT) + for file in $(KEEP); do \ + if test -r $(SERVERROOT)/$$file ; then \ + $(INSTALL_DATA) $$file $(SERVERROOT)/$$file.N ; \ + else \ + $(INSTALL_DATA) $$file $(SERVERROOT) ; \ + fi ; \ + done + for file in $(REPLACE); do \ + if test -r $(SERVERROOT)/$$file ; then \ + $(MV) $(SERVERROOT)/$$file $(SERVERROOT)/$$file.O ; \ + fi ; \ + $(INSTALL_DATA) $$file $(SERVERROOT) ; \ + done + + +# +# End of "$Id$". +# diff --git a/conf/classes.conf b/conf/classes.conf new file mode 100644 index 0000000000..f47c846e42 --- /dev/null +++ b/conf/classes.conf @@ -0,0 +1,89 @@ +# +# "$Id: classes.conf 1605 2001-03-02 22:34:21Z andy $" +# +# Sample class configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample class configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printer classes known to the system. # +# # +######################################################################## + +# +# Each class starts with a definition. Class names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes +# the default. +# + +# +# +# Info: the description for the class. +# + +#Info Acme LaserPrint 1000 Printers + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# State: sets the initial state of the class. Can be one of the +# following: +# +# Idle - Class is available to print new jobs. +# Stopped - Class is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the class. +# + +#StateMessage Class is idle. + +# +# Accepting: is the class accepting jobs? +# +#Accepting Yes +#Accepting No +# + +# +# Printer: adds a printer to the class. +# + +#Printer sample +#Printer sample@host2 +# + +# +# End of "$Id: classes.conf 1605 2001-03-02 22:34:21Z andy $". +# diff --git a/conf/client.conf b/conf/client.conf new file mode 100644 index 0000000000..5fbe4a2045 --- /dev/null +++ b/conf/client.conf @@ -0,0 +1,65 @@ +# +# "$Id: client.conf 1605 2001-03-02 22:34:21Z andy $" +# +# Sample client configuration file for the Common UNIX Printing System +# (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is the CUPS client configuration file. This file is used to # +# define client-specific parameters, such as the default server or # +# default encryption settings. # +# # +######################################################################## + +# +# ServerName: the hostname of your server. By default CUPS will use the +# hostname of the system or the value of the CUPS_SERVER environment +# variable. +# + +#ServerName myhost.domain.com + +# +# Encryption: whether or not to use encryption; this depends on having +# the OpenSSL library linked into the CUPS library. +# +# Possible values: +# +# Always - Always use encryption (SSL) +# Never - Never use encryption +# Required - Use TLS encryption upgrade +# IfRequested - Use encryption if the server requests it +# +# The default value is "IfRequested". This parameter can also be set +# using the CUPS_ENCRYPTION environment variable. +# + +#Encryption Always +#Encryption Never +#Encryption Required +#Encryption IfRequested + + +# +# End of "$Id: client.conf 1605 2001-03-02 22:34:21Z andy $". +# diff --git a/conf/cupsd.conf b/conf/cupsd.conf new file mode 100644 index 0000000000..5709577c9c --- /dev/null +++ b/conf/cupsd.conf @@ -0,0 +1,639 @@ +# +# "$Id: cupsd.conf 1631 2001-03-14 13:45:35Z mike $" +# +# Sample configuration file for the Common UNIX Printing System (CUPS) +# scheduler. +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is the CUPS configuration file. If you are familiar with # +# Apache or any of the other popular web servers, we've followed the # +# same format. Any configuration variable used here has the same # +# semantics as the corresponding variable in Apache. If we need # +# different functionality then a different name is used to avoid # +# confusion... # +# # +######################################################################## + + +######## +######## Server Identity +######## + +# +# ServerName: the hostname of your server, as advertised to the world. +# By default CUPS will use the hostname of the system. +# +# To set the default server used by clients, see the client.conf file. +# + +#ServerName myhost.domain.com + +# +# ServerAdmin: the email address to send all complaints/problems to. +# By default CUPS will use "root@hostname". +# + +#ServerAdmin root@your.domain.com + + +######## +######## Server Options +######## + +# +# AccessLog: the access log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "/var/log/cups/access_log" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#AccessLog /var/log/cups/access_log + +# +# Classification: the classification level of the server. If set, this +# classification is displayed on all pages, and raw printing is disabled. +# The default is the empty string. + +#Classification classified +#Classification confidential +#Classification secret +#Classification topsecret +#Classification unclassified + +# +# DataDir: the root directory for the CUPS data files. +# By default /usr/share/cups. +# + +#DataDir /usr/share/cups + +# +# DefaultCharset: the default character set to use. If not specified, +# defaults to utf-8. Note that this can also be overridden in +# HTML documents... +# + +#DefaultCharset utf-8 + +# +# DefaultLanguage: the default language if not specified by the browser. +# If not specified, the current locale is used. +# + +#DefaultLanguage en + +# +# DocumentRoot: the root directory for HTTP documents that are served. +# By default the compiled in directory. +# + +#DocumentRoot /usr/share/doc/cups + +# +# ErrorLog: the error log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "/var/log/cups/error_log" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#ErrorLog /var/log/cups/error_log + +# +# FontPath: the path to locate all font files (currently only for pstoraster) +# By default /usr/share/cups/fonts. +# + +#FontPath /usr/share/cups/fonts + +# +# LogLevel: controls the number of messages logged to the ErrorLog +# file and can be one of the following: +# +# debug2 Log everything. +# debug Log almost everything. +# info Log all requests and state changes. +# warn Log errors and warnings. +# error Log only errors. +# none Log nothing. +# + +LogLevel info + +# +# MaxLogSize: controls the maximum size of each log file before they are +# rotated. Defaults to 1048576 (1MB). Set to 0 to disable log rotating. +# + +#MaxLogSize 0 + +# +# PageLog: the page log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "/var/log/cups/page_log" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#PageLog /var/log/cups/page_log + +# +# PreserveJobHistory: whether or not to preserve the job history after a +# job is completed, cancelled, or stopped. Default is Yes. +# + +#PreserveJobHistory Yes + +# +# PreserveJobFiles: whether or not to preserve the job files after a +# job is completed, cancelled, or stopped. Default is No. +# + +#PreserveJobFiles No + +# +# AutoPurgeJobs: automatically purge jobs when not needed for quotas. +# Default is No. +# + +#AutoPurgeJobs No + +# +# MaxJobs: maximum number of jobs to keep in memory (active and completed.) +# Default is 0 (no limit.) +# + +#MaxJobs 0 + +# +# Printcap: the name of the printcap file. Default is /etc/printcap. +# Leave blank to disable printcap file generation. +# + +#Printcap /etc/printcap + +# +# RequestRoot: the directory where request files are stored. +# By default /var/spool/cups. +# + +#RequestRoot /var/spool/cups + +# +# RemoteRoot: the name of the user assigned to unauthenticated accesses +# from remote systems. By default "remroot". +# + +#RemoteRoot remroot + +# +# ServerBin: the root directory for the scheduler executables. +# By default /usr/lib/cups or /usr/lib32/cups (IRIX 6.5). +# + +#ServerBin /usr/lib/cups + +# +# ServerRoot: the root directory for the scheduler. +# By default /etc/cups. +# + +#ServerRoot /etc/cups + + +######## +######## Encryption Support +######## + +# +# ServerCertificate: the file to read containing the server's certificate. +# Defaults to "/etc/cups/ssl/server.crt". +# + +#ServerCertificate /etc/cups/ssl/server.crt + +# +# ServerKey: the file to read containing the server's key. +# Defaults to "/etc/cups/ssl/server.key". +# + +#ServerKey /etc/cups/ssl/server.key + + +######## +######## Filter Options +######## + +# +# User/Group: the user and group the server runs under. Normally this +# must be lp and sys, however you can configure things for another user +# or group as needed. +# +# Note: the server must be run initially as root to support the +# default IPP port of 631. It changes users whenever an external +# program is run... +# + +#User lp +#Group sys + +# +# RIPCache: the amount of memory that each RIP should use to cache +# bitmaps. The value can be any real number followed by "k" for +# kilobytes, "m" for megabytes, "g" for gigabytes, or "t" for tiles +# (1 tile = 256x256 pixels.) Defaults to "8m" (8 megabytes). +# + +#RIPCache 8m + +# +# TempDir: the directory to put temporary files in. This directory must be +# writable by the user defined above! Defaults to "/var/spool/cups/tmp" or +# the value of the TMPDIR environment variable. +# + +#TempDir /var/spool/cups/tmp + +# +# FilterLimit: sets the maximum cost of all job filters that can be run +# at the same time. A limit of 0 means no limit. A typical job may need +# a filter limit of at least 200; limits less than the minimum required +# by a job force a single job to be printed at any time. +# +# The default limit is 0 (unlimited). +# + +#FilterLimit 0 + +######## +######## Network Options +######## + +# +# Ports/addresses that we listen to. The default port 631 is reserved +# for the Internet Printing Protocol (IPP) and is what we use here. +# +# You can have multiple Port/Listen lines to listen to more than one +# port or address, or to restrict access: +# +# Port 80 +# Port 631 +# Listen hostname +# Listen hostname:80 +# Listen hostname:631 +# Listen 1.2.3.4 +# Listen 1.2.3.4:631 +# +# NOTE: Unfortunately, most web browsers don't support TLS or HTTP Upgrades +# for encryption. If you want to support web-based encryption you'll +# probably need to listen on port 443 (the "https" port...) +# + +#Port 80 +#Port 443 +Port 631 + +# +# HostNameLookups: whether or not to do lookups on IP addresses to get a +# fully-qualified hostname. This defaults to Off for performance reasons... +# + +#HostNameLookups On + +# +# KeepAlive: whether or not to support the Keep-Alive connection +# option. Default is on. +# + +#KeepAlive On + +# +# KeepAliveTimeout: the timeout before Keep-Alive connections are +# automatically closed. Default is 60 seconds. +# + +#KeepAliveTimeout 60 + +# +# MaxClients: controls the maximum number of simultaneous clients that +# will be handled. Defaults to 100. +# + +#MaxClients 100 + +# +# MaxRequestSize: controls the maximum size of HTTP requests and print files. +# Set to 0 to disable this feature (defaults to 0.) +# + +#MaxRequestSize 0 + +# +# Timeout: the timeout before requests time out. Default is 300 seconds. +# + +#Timeout 300 + + +######## +######## Browsing Options +######## + +# +# Browsing: whether or not to broadcast and/or listen for CUPS printer +# information on the network. Enabled by default. +# + +#Browsing On + +# +# BrowseAddress: specifies a broadcast address to be used. By +# default browsing information is not sent! +# +# Note: HP-UX does not properly handle broadcast unless you have a +# Class A, B, C, or D netmask (i.e. no CIDR support). +# +# Note: Using the "global" broadcast address (255.255.255.255) will +# activate a Linux demand-dial link with the default configuration. +# If you have a LAN as well as the dial-up link, use the LAN's +# broadcast address. +# + +#BrowseAddress x.y.z.255 +#BrowseAddress x.y.255.255 +#BrowseAddress x.255.255.255 +#BrowseAddress 255.255.255.255 + +# +# BrowseShortNames: whether or not to use "short" names for remote printers +# when possible (e.g. "printer" instead of "printer@host".) Enabled by +# default. +# + +#BrowseShortNames Yes + +# +# BrowseAllow: specifies an address mask to allow for incoming browser +# packets. The default is to allow packets from all addresses. +# +# BrowseDeny: specifies an address mask to deny for incoming browser +# packets. The default is to deny packets from no addresses. +# +# Both "BrowseAllow" and "BrowseDeny" accept the following notations for +# addresses: +# +# All +# None +# *.domain.com +# .domain.com +# host.domain.com +# nnn.* +# nnn.nnn.* +# nnn.nnn.nnn.* +# nnn.nnn.nnn.nnn +# nnn.nnn.nnn.nnn/mm +# nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm +# +# The hostname/domainname restrictions only work if you have turned hostname +# lookups on! +# + +#BrowseAllow address +#BrowseDeny address + +# +# BrowseInterval: the time between browsing updates in seconds. Default +# is 30 seconds. +# +# Note that browsing information is sent whenever a printer's state changes +# as well, so this represents the maximum time between updates. +# +# Set this to 0 to disable outgoing broadcasts so your local printers are +# not advertised but you can still see printers on other hosts. +# + +#BrowseInterval 30 + +# +# BrowseOrder: specifies the order of BrowseAllow/BrowseDeny comparisons. +# + +#BrowseOrder allow,deny +#BrowseOrder deny,allow + +# +# BrowsePoll: poll the named server(s) for printers +# + +#BrowsePoll address:port + +# +# BrowsePort: the port used for UDP broadcasts. By default this is +# the IPP port; if you change this you need to do it on all servers. +# Only one BrowsePort is recognized. +# + +#BrowsePort 631 + +# +# BrowseRelay: relay browser packets from one address/network to another. +# + +#BrowseRelay source-address destination-address + +# +# BrowseTimeout: the timeout for network printers - if we don't +# get an update within this time the printer will be removed +# from the printer list. This number definitely should not be +# less the BrowseInterval value for obvious reasons. Defaults +# to 300 seconds. +# + +#BrowseTimeout 300 + +# +# ImplicitClasses: whether or not to use implicit classes. +# +# Printer classes can be specified explicitly in the classes.conf +# file, implicitly based upon the printers available on the LAN, or +# both. +# +# When ImplicitClasses is On, printers on the LAN with the same name +# (e.g. Acme-LaserPrint-1000) will be put into a class with the same +# name. This allows you to setup multiple redundant queues on a LAN +# without a lot of administrative difficulties. If a user sends a +# job to Acme-LaserPrint-1000, the job will go to the first available +# queue. +# +# Enabled by default. +# + +#ImplicitClasses On + + +######## +######## Security Options +######## + +# +# SystemGroup: the group name for "System" (printer administration) +# access. The default varies depending on the operating system, but +# will be "sys", "system", or "root" (checked for in that order.) +# + +#SystemGroup sys + +# +# Access permissions for each directory served by the scheduler. +# Locations are relative to DocumentRoot... +# +# AuthType: the authorization to use: +# +# None - Perform no authentication +# Basic - Perform authentication using the HTTP Basic method. +# Digest - Perform authentication using the HTTP Digest method. +# +# (Note: local certificate authentication can be substituted by +# the client for Basic or Digest when connecting to the +# localhost interface) +# +# AuthClass: the authorization class; currently only "Anonymous", "User", +# "System" (valid user belonging to group SystemGroup), and "Group" +# (valid user belonging to the specified group) are supported. +# +# AuthGroupName: the group name for "Group" authorization. +# +# Order: the order of Allow/Deny processing. +# +# Allow: allows access from the specified hostname, domain, IP address, or +# network. +# +# Deny: denies access from the specified hostname, domain, IP address, or +# network. +# +# Both "Allow" and "Deny" accept the following notations for addresses: +# +# All +# None +# *.domain.com +# .domain.com +# host.domain.com +# nnn.* +# nnn.nnn.* +# nnn.nnn.nnn.* +# nnn.nnn.nnn.nnn +# nnn.nnn.nnn.nnn/mm +# nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm +# +# The host and domain address require that you enable hostname lookups +# with "HostNameLookups On" above. +# +# Encryption: whether or not to use encryption; this depends on having +# the OpenSSL library linked into the CUPS library and scheduler. +# +# Possible values: +# +# Always - Always use encryption (SSL) +# Never - Never use encryption +# Required - Use TLS encryption upgrade +# IfRequested - Use encryption if the server requests it +# +# The default value is "IfRequested". +# + + +Order Deny,Allow +Deny From All +Allow From 127.0.0.1 + + +# +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# +# + +# +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# +# + +# +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# +# + +# +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# + +## Anonymous access (default) +#AuthType None + +## Require a username and password (Basic authentication) +#AuthType Basic +#AuthClass User + +## Require a username and password (Digest/MD5 authentication) +#AuthType Digest +#AuthClass User + +## Restrict access to local domain +#Order Deny,Allow +#Deny From All +#Allow From .mydomain.com +# + + +# +# You definitely will want to limit access to the administration functions. +# The default configuration requires a local connection from a user who +# is a member of the system group to do any admin tasks. You can change +# the group name using the SystemGroup directive. +# + +AuthType Basic +AuthClass System + +## Restrict access to local domain +Order Deny,Allow +Deny From All +Allow From 127.0.0.1 + +#Encryption Required + + +# +# End of "$Id: cupsd.conf 1631 2001-03-14 13:45:35Z mike $". +# diff --git a/conf/mime.convs b/conf/mime.convs new file mode 100644 index 0000000000..2e751199e0 --- /dev/null +++ b/conf/mime.convs @@ -0,0 +1,78 @@ +# +# "$Id: mime.convs 1605 2001-03-02 22:34:21Z andy $" +# +# MIME converts file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# Format of Lines: +# +# source/type destination/type cost filter +# +# General Notes: +# +# Currently the "cost" field is not used (all filters are assumed to +# be equally costly in terms of speed/memory). Also, a filter program +# *must* accept the standard command-line arguments (job-id, user, title, +# copies,options,[filename or stdin]) or this won't work. +# + +######################################################################## +# +# PostScript filters +# + +#application/msword application/postscript 33 mswordtops +application/pdf application/postscript 33 pdftops +application/postscript application/vnd.cups-postscript 66 pstops +application/vnd.hp-HPGL application/postscript 66 hpgltops +image/* application/vnd.cups-postscript 66 imagetops +#text/html application/postscript 33 htmltops +application/x-cshell application/postscript 33 texttops +application/x-perl application/postscript 33 texttops +application/x-shell application/postscript 33 texttops +text/html application/postscript 33 texttops +text/plain application/postscript 33 texttops +application/vnd.cups-form application/vnd.cups-postscript 33 formtops + +######################################################################## +# +# Raster filters... +# + +image/* application/vnd.cups-raster 100 imagetoraster +application/vnd.cups-postscript application/vnd.cups-raster 100 pstoraster + +######################################################################## +# +# Raw filter... +# +# Uncomment the following filter and the application/octet-stream type +# in mime.types to allow printing of arbitrary files without the -oraw +# option. +# + +#*/* application/vnd.cups-raw 0 - + +# +# End of "$Id: mime.convs 1605 2001-03-02 22:34:21Z andy $". +# diff --git a/conf/mime.types b/conf/mime.types new file mode 100644 index 0000000000..5cb408efaf --- /dev/null +++ b/conf/mime.types @@ -0,0 +1,155 @@ +# +# "$Id: mime.types 1681 2001-04-19 15:42:39Z mike $" +# +# MIME types file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# Format of Lines: +# +# super/type rules +# +# "rules" can be any combination of: +# +# ( expr ) Parenthesis for expression grouping +# + Logical AND +# , or whitespace Logical OR +# ! Logical NOT +# match("pattern") Pattern match on filename +# extension Pattern match on "*.extension" +# ascii(offset,length) True if bytes are valid printable ASCII +# (CR, NL, TAB, BS, 32-126) +# printable(offset,length) True if bytes are printable 8-bit chars +# (CR, NL, TAB, BS, 32-126, 128-254) +# string(offset,"string") True if bytes are identical to string +# char(offset,value) True if byte is identical +# short(offset,value) True if 16-bit integer is identical +# int(offset,value) True if 32-bit integer is identical +# locale("string") True if current locale matches string +# contains(offset,range,"string") True if the range contains the string +# +# General Notes: +# +# MIME type names are case-insensitive. Internally they are converted +# to lowercase. Multiple occurrences of a type will cause the provided +# rules to be appended to the existing definition. Type names are sorted +# in ascending order, so if two types use the same rules to resolve a type +# (e.g. doc extension for two types), the returned type will be the first +# type in the sorted list. +# +# The "printable" rule differs from the "ascii" rule in that it also +# accepts 8-bit characters in the range 128-255. +# +# String constants must be surrounded by "" if they contain whitespace. +# To insert binary data into a string, use the notation. +# + +######################################################################## +# +# Application-generated files... +# + +application/msword doc string(0,) +application/pdf pdf string(0,%PDF) +application/postscript ai eps ps string(0,%!) string(0,<04>%!) +application/vnd.hp-HPGL hpgl string(0,<1B>&)\ + string(0,<1B>E<1B>%0B) string(0,<201B>)\ + string(0,BP;) string(0,IN;) string(0,DF;) \ + string(0,BPINPS;) \ + (string(0,<1B>%-12345X) + \ + (contains(9,512,"LANGUAGE=HPGL") \ + contains(9,512,"LANGUAGE = HPGL"))) + +######################################################################## +# +# Image files... +# + +image/gif gif string(0,GIF87a) string(0,GIF89a) +image/png png string(0,<89>PNG) +image/jpeg jpeg jpg jpe string(0,) &&\ + (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\ + char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\ + char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\ + char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef)) +image/tiff tiff tif string(0,MM) string(0,II) +image/x-photocd pcd string(2048,PCD_IPI) +image/x-portable-anymap pnm +image/x-portable-bitmap pbm string(0,P1) string(0,P4) +image/x-portable-graymap pgm string(0,P2) string(0,P5) +image/x-portable-pixmap ppm string(0,P3) string(0,P6) +image/x-sgi-rgb rgb sgi bw icon short(0,474) +image/x-xbitmap xbm +image/x-xpixmap xpm ascii(0,1024) + string(3,"XPM") +image/x-xwindowdump xwd +image/x-sun-raster ras string(0,<59a66a95>) + +#image/fpx fpx +image/x-alias pix short(8,8) short(8,24) +image/x-bitmap bmp string(0,BM) && !printable(2,14) + +######################################################################## +# +# Text files... +# + +text/html html htm printable(0,1024) +\ + (string(0,"") string(0,"") +application/vnd.cups-postscript string(0,<1B>%-12345X) + \ + (contains(9,512,"LANGUAGE=POSTSCRIPT") \ + contains(9,512,"LANGUAGE = POSTSCRIPT")) +application/vnd.cups-raster string(0,"RaSt") string(0,"tSaR") +application/vnd.cups-raw (string(0,<1B>E) + !string(2,<1B>%0B)) \ + string(0,<1B>@) \ + (string(0,<1B>%-12345X) + \ + (contains(9,512,"LANGUAGE=PCL") \ + contains(9,512,"LANGUAGE = PCL"))) + +######################################################################## +# +# Raw print file support... +# +# Uncomment the following type and the application/octet-stream +# filter line in mime.convs to allow raw file printing without the +# -oraw option. +# + +#application/octet-stream + +# +# End of "$Id: mime.types 1681 2001-04-19 15:42:39Z mike $". +# diff --git a/conf/printcap b/conf/printcap new file mode 100644 index 0000000000..230c3017d6 --- /dev/null +++ b/conf/printcap @@ -0,0 +1,2 @@ +# This is a dummy printcap file that is automatically generated by the +# CUPS software for old applications that rely on it. diff --git a/conf/printers.conf b/conf/printers.conf new file mode 100644 index 0000000000..0e13084e24 --- /dev/null +++ b/conf/printers.conf @@ -0,0 +1,96 @@ +# +# "$Id: printers.conf 1605 2001-03-02 22:34:21Z andy $" +# +# Sample printer configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample printer configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printers known to the system. # +# # +######################################################################## + +# +# Each printer starts with a definition. Printer names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes the +# default. +# + +# +# +# Info: the description for the printer. +# + +#Info Acme LaserPrint 1000 + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# DeviceURI: the device URI for this printer. +# + +#DeviceURI parallel:/dev/plp +#DeviceURI serial:/dev/ttyd1?baud=38400+size=8+parity=none+flow=soft +#DeviceURI scsi:/dev/scsi/sc1d6l0 +#DeviceURI socket://hostname:port +#DeviceURI tftp://hostname/path +#DeviceURI ftp://hostname/path +#DeviceURI http://hostname[:port]/path +#DeviceURI ipp://hostname/path +#DeviceURI smb://hostname/printer + +# +# State: sets the initial state of the printer. Can be one of the +# following: +# +# Idle - Printer is available to print new jobs. +# Stopped - Printer is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the printer. +# + +#StateMessage Printer is idle. + +# +# Accepting: is the printer accepting jobs? +# +#Accepting Yes +#Accepting No + +# + +# +# End of "$Id: printers.conf 1605 2001-03-02 22:34:21Z andy $". +# diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000..913ad1e933 --- /dev/null +++ b/config.h.in @@ -0,0 +1,152 @@ +/* + * "$Id$" + * + * Configuration file for the Common UNIX Printing System (CUPS). + * + * @configure_input@ + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Version of software... + */ + +#define CUPS_SVERSION "CUPS v1.1.7" + +/* + * Where are files stored? + */ + +#define CUPS_LOCALEDIR "/usr/share/locale" +#define CUPS_SERVERROOT "/etc/cups" +#define CUPS_SERVERBIN "/usr/lib/cups" +#define CUPS_DOCROOT "/usr/share/doc/cups" +#define CUPS_REQUESTS "/var/spool/cups" +#define CUPS_LOGDIR "/var/logs/cups" +#define CUPS_DATADIR "/usr/share/cups" +#define CUPS_FONTPATH "/usr/share/cups/fonts" + +/* + * What is the format string for strftime? + */ + +#define CUPS_STRFTIME_FORMAT NULL + +/* + * Do we have various image libraries? + */ + +#undef HAVE_LIBPNG +#undef HAVE_LIBZ +#undef HAVE_LIBJPEG +#undef HAVE_LIBTIFF + +/* + * Does this machine store words in big-endian (MSB-first) order? + */ + +#undef WORDS_BIGENDIAN + +/* + * Which directory functions and headers do we use? + */ + +#undef HAVE_DIRENT_H +#undef HAVE_SYS_DIR_H +#undef HAVE_SYS_NDIR_H +#undef HAVE_NDIR_H + +/* + * Do we have PAM stuff? + */ + +#ifndef HAVE_LIBPAM +#define HAVE_LIBPAM 0 +#endif /* !HAVE_LIBPAM */ + +/* + * Do we have ? + */ + +#undef HAVE_SHADOW_H + +/* + * Do we have ? + */ + +#undef HAVE_CRYPT_H + +/* + * Do we have the strXXX() functions? + */ + +#undef HAVE_STRDUP +#undef HAVE_STRCASECMP +#undef HAVE_STRNCASECMP + +/* + * Do we have the vsyslog() function? + */ + +#undef HAVE_VSYSLOG + +/* + * Do we have the (v)snprintf() functions? + */ + +#undef HAVE_SNPRINTF +#undef HAVE_VSNPRINTF + +/* + * What signal functions to use? + */ + +#undef HAVE_SIGSET +#undef HAVE_SIGACTION + +/* + * What wait functions to use? + */ + +#undef HAVE_WAITPID +#undef HAVE_WAIT3 + +/* + * Do we have the mallinfo function and malloc.h? + */ + +#undef HAVE_MALLINFO +#undef HAVE_MALLOC_H + +/* + * Do we have the OpenSSL library? + */ + +#undef HAVE_LIBSSL + +/* + * Do we have ? + */ + +#undef HAVE_SYS_IOCTL_H + +/* + * End of "$Id$". + */ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000000..89d6942b51 --- /dev/null +++ b/configure.in @@ -0,0 +1,670 @@ +dnl +dnl "$Id$" +dnl +dnl Configuration script for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2001 by Easy Software Products, all rights reserved. +dnl +dnl These coded instructions, statements, and computer programs are the +dnl property of Easy Software Products and are protected by Federal +dnl copyright law. Distribution and use rights are outlined in the file +dnl "LICENSE.txt" which should have been included with this file. If this +dnl file is missing or damaged please contact Easy Software Products +dnl at: +dnl +dnl Attn: CUPS Licensing Information +dnl Easy Software Products +dnl 44141 Airport View Drive, Suite 204 +dnl Hollywood, Maryland 20636-3111 USA +dnl +dnl Voice: (301) 373-9603 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +AC_INIT(cups/cups.h) +AC_CONFIG_HEADER(config.h) +AC_PREFIX_DEFAULT(/) + +dnl Get the operating system and version number... + +uname=`uname` +uversion=`uname -r | sed -e '1,$s/[[^0-9]]//g'` +if test "$uname" = "IRIX64"; then + uname="IRIX" +fi + +dnl Clear the debugging and non-shared library options unless the user asks +dnl for them... + +OPTIM="" +AC_SUBST(OPTIM) +PICFLAG=1 +CFLAGS="${CFLAGS:=}" +CXXFLAGS="${CXXFLAGS:=}" +DSOFLAGS="${DSOFLAGS:=}" +AC_SUBST(DSOFLAGS) + +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]],[if eval "test x$enable_debug = xyes"; then + OPTIM="-g" +fi]) +AC_ARG_ENABLE(shared, [ --enable-shared turn on shared libraries [default=yes]]) +AC_ARG_ENABLE(ssl, [ --enable-ssl turn on SSL/TLS support [default=no]]) +AC_ARG_ENABLE(libtool_unsupported, [ --enable-libtool-unsupported=LIBTOOL_PATH + turn on building with libtool (UNSUPPORTED!) [default=no]],[if eval "test x$enable_libtool_unsupported != xno"; then + LIBTOOL="$enable_libtool_unsupported" + enable_shared=no + echo "WARNING: libtool is not supported or endorsed by Easy Software Products." + echo " WE DO NOT PROVIDE TECHNICAL SUPPORT FOR LIBTOOL PROBLEMS." + echo " (even if you have a support contract)" +else + LIBTOOL="" +fi]) + +if test "$enable_shared" != "no"; then + case "$uname" in + SunOS* | UNIX_S*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-h,\$@ -G \$(OPTIM)" + ;; + HP-UX*) + LIBCUPS="libcups.sl.2" + LIBCUPSIMAGE="libcupsimage.sl.2" + DSO="ld" + DSOFLAGS="$DSOFLAGS -b -z +h \$@" + ;; + FreeBSD* | NetBSD* | OpenBSD*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)" + ;; + OSF1* | Linux*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)" + ;; + IRIX*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -soname \$@ -shared \$(OPTIM)" + ;; + *) + echo "Warning: shared libraries may not be supported. Trying -shared" + echo " option with compiler." + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)" + ;; + esac +else + PICFLAG=0 + LIBCUPS="libcups.a" + LIBCUPSIMAGE="libcupsimage.a" + DSO=":" +fi + +if test "$LIBTOOL" != ""; then + LIBCUPS="libcups.la" + LIBCUPSIMAGE="libcupsimage.la" + LINKCUPS="../cups/\$(LIBCUPS)" + LINKCUPSIMAGE="../filter/\$(LIBCUPSIMAGE)" + DSO=":" + DSOFLAGS="" +else + LINKCUPS="-L../cups -lcups" + LINKCUPSIMAGE="-L../filter -lcupsimage" +fi + +AC_ARG_ENABLE(pam, [ --enable-pam turn on PAM support [default=yes]]) + +AC_ARG_WITH(fontpath, [ --with-fontpath set font path for pstoraster],fontpath="$withval",fontpath="") + +AC_ARG_WITH(docdir, [ --with-docdir set path for documentation],docdir="$withval",docdir="") + +dnl Checks for programs... +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CXX +AC_PROG_CPP +AC_PROG_RANLIB +AC_PATH_PROG(AR,ar) +AC_PATH_PROG(CHMOD,chmod) +AC_PATH_PROG(CHOWN,chown) +AC_PATH_PROG(CP,cp) +AC_PATH_PROG(MV,mv) +AC_PATH_PROG(NROFF,nroff) +if test "$NROFF" = ""; then + AC_PATH_PROG(GROFF,groff) + if test "$GROFF" = ""; then + NROFF="echo" + else + NROFF="$GROFF -T ascii" + fi +fi +AC_PATH_PROG(HTMLDOC,htmldoc) +AC_PATH_PROG(MKDIR,mkdir) +AC_PATH_PROG(RM,rm) +AC_PATH_PROG(SED,sed) + +dnl Architecture checks... +AC_C_BIGENDIAN + +dnl Check for libraries... +AC_CHECK_LIB(c,crypt,LIBS="$LIBS") +if test "$ac_cv_lib_c_crypt" = "no"; then + AC_CHECK_LIB(crypt,crypt) +fi +AC_CHECK_LIB(sec,getspent) + +LIBMALLOC="" +AC_CHECK_LIB(c,mallinfo,LIBS="$LIBS"; AC_DEFINE(HAVE_MALLINFO),LIBS="$LIBS") +if test "$ac_cv_lib_c_mallinfo" = "no"; then + AC_CHECK_LIB(malloc,mallinfo, + LIBS="$LIBS" + LIBMALLOC="-lmalloc" + AC_DEFINE(HAVE_MALLINFO), + LIBS="$LIBS") +fi +AC_SUBST(LIBMALLOC) + +if test "$enable_pam" != "no"; then + OLDLIBS="$LIBS" + AC_CHECK_LIB(dl,dlopen) + AC_CHECK_LIB(pam,pam_start) + if test "$ac_cv_lib_pam_pam_start" != "no"; then + PAMDIR="/etc/pam.d" + else + PAMDIR="" + LIBS="$OLDLIBS" + fi + AC_SUBST(PAMDIR) +fi + +NETLIBS="" +AC_SUBST(NETLIBS) +AC_CHECK_LIB(socket,socket, +if test "$uname" != "IRIX"; then + NETLIBS="-lsocket" +else + echo "Not using -lsocket since you are running IRIX." +fi) +AC_CHECK_LIB(nsl,gethostbyaddr, +if test "$uname" != "IRIX"; then + NETLIBS="$NETLIBS -lnsl" +else + echo "Not using -lnsl since you are running IRIX." +fi) + +dnl Encryption support... + +SSLLIBS="" +AC_SUBST(SSLLIBS) + +if test "$enable_ssl" = "yes"; then + dnl Save the current libraries so the crypto stuff isn't always + dnl included... + SAVELIBS="$LIBS" + + dnl Some ELF systems can't resolve all the symbols in libcrypto + dnl if libcrypto was linked against RSAREF, and fail to link the + dnl test program correctly, even though a correct installation + dnl of OpenSSL exists. So we test the linking three times in + dnl case the RSAREF libraries are needed. + + for libcrypto in \ + "-lcrypto" \ + "-lcrypto -lrsaref" \ + "-lcrypto -lRSAglue -lrsaref" + do + AC_CHECK_LIB(ssl,SSL_new, + [SSLLIBS="-lssl $libcrypto" + AC_DEFINE(HAVE_LIBSSL)],, + $libcrypto + ) + if test "x${SSLLIBS}" != "x"; then + break + fi + done + + LIBS="$SAVELIBS" +fi + +dnl Save the current libraries since we don't want the image libraries +dnl included with every program... +SAVELIBS="$LIBS" + +dnl Check for image libraries... +LIBJPEG="" +LIBPNG="" +LIBTIFF="" +LIBZ="" + +AC_SUBST(LIBJPEG) +AC_SUBST(LIBPNG) +AC_SUBST(LIBTIFF) +AC_SUBST(LIBZ) + +AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + AC_DEFINE(HAVE_LIBJPEG) + LIBJPEG="-ljpeg" + LIBS="$LIBS -ljpeg") + +AC_CHECK_LIB(z, gzgets, + AC_DEFINE(HAVE_LIBZ) + LIBZ="-lz" + LIBS="$LIBS -lz") + +dnl PNG library uses math library functions... +AC_CHECK_LIB(m, pow) + +AC_CHECK_LIB(png, png_set_tRNS_to_alpha, + AC_DEFINE(HAVE_LIBPNG) + LIBPNG="-lpng") + +AC_CHECK_LIB(tiff, TIFFReadScanline, + AC_DEFINE(HAVE_LIBTIFF) + LIBTIFF="-ltiff") + +dnl Restore original LIBS settings... +LIBS="$SAVELIBS" + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_DIRENT +AC_CHECK_HEADER(crypt.h,AC_DEFINE(HAVE_CRYPT_H)) +AC_CHECK_HEADER(malloc.h,AC_DEFINE(HAVE_MALLOC_H)) +AC_CHECK_HEADER(shadow.h,AC_DEFINE(HAVE_SHADOW_H)) +AC_CHECK_HEADER(stddef.h,AC_DEFINE(HAVE_STDDEF_H)) +AC_CHECK_HEADER(stdlib.h,AC_DEFINE(HAVE_STDLIB_H)) +AC_CHECK_HEADER(sys/ioctl.h,AC_DEFINE(HAVE_SYS_IOCTL_H)) + +dnl Checks for string functions. +AC_CHECK_FUNCS(strdup) +AC_CHECK_FUNCS(strcasecmp) +AC_CHECK_FUNCS(strncasecmp) +if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then + echo Forcing snprintf emulation for HP-UX. +else + AC_CHECK_FUNCS(snprintf) + AC_CHECK_FUNCS(vsnprintf) +fi + +dnl Check OS version and use appropriate format string for strftime... +AC_MSG_CHECKING(for correct format string to use with strftime) + +case "$uname" in + IRIX* | SunOS*) + # IRIX and SunOS + AC_MSG_RESULT(NULL) + AC_DEFINE(CUPS_STRFTIME_FORMAT, NULL) + ;; + *) + # All others + AC_MSG_RESULT("%c") + AC_DEFINE(CUPS_STRFTIME_FORMAT, "%c") + ;; +esac + +dnl Checks for vsyslog function. +AC_CHECK_FUNCS(vsyslog) + +dnl Checks for signal functions. +if test "$uname" != "Linux"; then + AC_CHECK_FUNCS(sigset) +fi + +AC_CHECK_FUNCS(sigaction) + +dnl Checks for wait functions. +AC_CHECK_FUNCS(waitpid) +AC_CHECK_FUNCS(wait3) + +dnl Update compiler options... +if test -n "$GCC"; then + CXX="$CC" + + if test -z "$OPTIM"; then + OPTIM="-O2" + fi + if test $PICFLAG = 1; then + OPTIM="-fPIC $OPTIM" + fi + OPTIM="-Wall $OPTIM" +else + case $uname in + IRIX*) + if test -z "$OPTIM"; then + OPTIM="-O2" + fi + if test $uversion -ge 62; then + OPTIM="$OPTIM -n32 -mips3" + fi + OPTIM="-fullwarn $OPTIM" + ;; + HP-UX*) + if test -z "$OPTIM"; then + OPTIM="+O2" + fi + CFLAGS="-Ae $CFLAGS" + OPTIM="+DAportable $OPTIM" + if test $PICFLAG = 1; then + OPTIM="+z $OPTIM" + fi + ;; + SunOS*) + # Solaris + if test -z "$OPTIM"; then + OPTIM="-xO4" + fi + OPTIM="$OPTIM -xarch=generic" + if test $PICFLAG = 1; then + OPTIM="-KPIC $OPTIM" + fi + ;; + *) + # Running some other operating system; inform the user they + # should contribute the necessary options to + # cups-support@cups.org... + echo "Building CUPS with default compiler optimizations; contact" + echo "cups-support@cups.org with uname and compiler options needed" + echo "for your platform, or set the CFLAGS environment variable" + echo "before running configure." + ;; + esac +fi + +if test "$DSO" != ":"; then + # When using DSOs the image libraries are linked to libcupsimage.so + # rather than to the executables. This makes things smaller if you + # are using any static libraries, and it also allows us to distribute + # a single DSO rather than a bunch... + DSOLIBS="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)" + IMGLIBS="" + + # The *BSD, HP-UX, and Solaris run-time linkers need help when + # deciding where to find a DSO. Add linker options to tell them + # where to find the DSO (usually in /usr/lib... duh!) + case $uname in + HP-UX*) + # HP-UX + DSOFLAGS="+b $libdir +fb $DSOFLAGS" + LDFLAGS="$LDFLAGS -Wl,+b,$libdir,+fb" + ;; + SunOS*) + # Solaris + DSOFLAGS="-R$libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -R$libdir" + ;; + FreeBSD* | NetBSD* | OpenBSD*) + # *BSD + DSOFLAGS="-Wl,-R$libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -Wl,-R$libdir" + ;; + esac +else + DSOLIBS="" + IMGLIBS="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)" +fi + +AC_SUBST(DSO) +AC_SUBST(DSOLIBS) +AC_SUBST(IMGLIBS) +AC_SUBST(LIBCUPS) +AC_SUBST(LIBCUPSIMAGE) +AC_SUBST(LIBTOOL) +AC_SUBST(LINKCUPS) +AC_SUBST(LINKCUPSIMAGE) + +dnl Fix "prefix" variable if it hasn't been specified... +if test "$prefix" = "NONE"; then + prefix="/" +fi + +dnl Fix "exec_prefix" variable if it hasn't been specified... +if test "$exec_prefix" = "NONE"; then + if test "$prefix" = "/"; then + exec_prefix="/usr" + else + exec_prefix="$prefix" + fi +fi + +dnl Fix "sharedstatedir" variable if it hasn't been specified... +if test "$sharedstatedir" = "\${prefix}/com" -a "$prefix" = "/"; then + sharedstatedir="/usr/com" +fi + +dnl Fix "datadir" variable if it hasn't been specified... +if test "$datadir" = "\${prefix}/share"; then + if test "$prefix" = "/"; then + datadir="/usr/share" + else + datadir="$prefix/share" + fi +fi + +dnl Fix "includedir" variable if it hasn't been specified... +if test "$includedir" = "\${prefix}/include" -a "$prefix" = "/"; then + includedir="/usr/include" +fi + +dnl Fix "localstatedir" variable if it hasn't been specified... +if test "$localstatedir" = "\${prefix}/var"; then + if test "$prefix" = "/"; then + localstatedir="/var" + else + localstatedir="$prefix/var" + fi +fi + +dnl Fix "sysconfdir" variable if it hasn't been specified... +if test "$sysconfdir" = "\${prefix}/etc"; then + if test "$prefix" = "/"; then + sysconfdir="/etc" + else + sysconfdir="$prefix/etc" + fi +fi + +dnl Fix "libdir" variable for IRIX 6.x... +if test "$uname" = "IRIX" -a $uversion -ge 62; then + libdir="$exec_prefix/lib32" +fi + +dnl Fix "mandir" variable... +if test "$mandir" = "\${prefix}/man" -a "$prefix" = "/"; then + case "$uname" in + FreeBSD* | NetBSD* | OpenBSD*) + # *BSD + mandir="/usr/share/man" + AMANDIR="/usr/share/man" + ;; + IRIX*) + # SGI IRIX + mandir="/usr/share/catman/u_man" + AMANDIR="/usr/share/catman/a_man" + ;; + *) + # All others + mandir="/usr/man" + AMANDIR="/usr/man" + ;; + esac +else + AMANDIR="$mandir" +fi + +AC_SUBST(AMANDIR) + +dnl Fix "fontpath" variable... +if test "x$fontpath" = "x"; then + fontpath="$datadir/cups/fonts" +fi + +dnl Setup manpage extensions... +case "$uname" in + FreeBSD* | NetBSD* | OpenBSD*) + # *BSD + CAT1EXT=0 + CAT5EXT=0 + CAT8EXT=0 + MAN8EXT=8 + ;; + IRIX*) + # SGI IRIX + CAT1EXT=z + CAT5EXT=z + CAT8EXT=z + MAN8EXT=1m + ;; + SunOS* | HP-UX*) + # Solaris and HP-UX + CAT1EXT=1 + CAT5EXT=5 + CAT8EXT=1m + MAN8EXT=1m + ;; + *) + # All others + CAT1EXT=1 + CAT5EXT=5 + CAT8EXT=8 + MAN8EXT=8 + ;; +esac + +AC_SUBST(CAT1EXT) +AC_SUBST(CAT5EXT) +AC_SUBST(CAT8EXT) +AC_SUBST(MAN8EXT) + +dnl Setup init.d locations... +case "$uname" in + FreeBSD* | OpenBSD*) + # FreeBSD and OpenBSD + INITDIR="" + INITDDIR="" + ;; + + NetBSD*) + # NetBSD + INITDIR="" + INITDDIR="/etc/rc.d" + ;; + + Linux*) + # Linux seems to choose an init.d directory at random... + if test -d /sbin/init.d; then + # SuSE + INITDIR="/sbin/init.d" + INITDDIR=".." + else + if test -d /etc/rc.d; then + # RedHat + INITDIR="/etc/rc.d" + INITDDIR="../init.d" + else + # Others + INITDIR="/etc" + INITDDIR="../init.d" + fi + fi + ;; + + OSF1* | HP-UX*) + INITDIR="/sbin" + INITDDIR="../init.d" + ;; + + *) + INITDIR="/etc" + INITDDIR="../init.d" + ;; + +esac + +AC_SUBST(INITDIR) +AC_SUBST(INITDDIR) + +dnl Setup default locations... +CUPS_SERVERROOT='${sysconfdir}/cups' +CUPS_LOGDIR='${localstatedir}/log/cups' +CUPS_REQUESTS='${localstatedir}/spool/cups' + +AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$sysconfdir/cups") +AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$localstatedir/log/cups") +AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$localstatedir/spool/cups") + +dnl See what directory to put server executables... +case "$uname" in + FreeBSD* | NetBSD* | OpenBSD*) + # *BSD + INSTALL_SYSV="" + CUPS_SERVERBIN='${exec_prefix}/libexec/cups' + AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$exec_prefix/libexec/cups") + ;; + *) + # All others + INSTALL_SYSV="install-sysv" + CUPS_SERVERBIN='${exec_prefix}/lib/cups' + AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$exec_prefix/lib/cups") + ;; +esac + +AC_SUBST(INSTALL_SYSV) +AC_SUBST(CUPS_SERVERROOT) +AC_SUBST(CUPS_SERVERBIN) +AC_SUBST(CUPS_LOGDIR) +AC_SUBST(CUPS_REQUESTS) + +dnl Set the CUPS_LOCALE directory... +case "$uname" in + Linux* | FreeBSD* | NetBSD* | OpenBSD*) + CUPS_LOCALEDIR='${datadir}/locale' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$datadir/locale") + ;; + + OSF1*) + CUPS_LOCALEDIR='${exec_prefix}/lib/nls/msg' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$exec_prefix/lib/nls/msg") + ;; + + *) + # This is the standard System V location... + CUPS_LOCALEDIR='${exec_prefix}/lib/locale' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$exec_prefix/lib/locale") + ;; +esac + +AC_SUBST(CUPS_LOCALEDIR) + +dnl Set the CUPS_DATADIR directory... +CUPS_DATADIR='${datadir}/cups' +AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$datadir/cups") +AC_SUBST(CUPS_DATADIR) + +dnl Set the CUPS_DOCROOT directory... +if test x$docdir = x; then + CUPS_DOCROOT='${datadir}/doc/cups' + docdir="$datadir/doc/cups" +else + CUPS_DOCROOT="$docdir" +fi + +AC_DEFINE_UNQUOTED(CUPS_DOCROOT, "$docdir") +AC_SUBST(CUPS_DOCROOT) + +dnl Set the CUPS_FONTPATH directory... +AC_DEFINE_UNQUOTED(CUPS_FONTPATH, "$fontpath") + +AC_OUTPUT(Makedefs cups.sh) + +dnl +dnl End of "$Id$". +dnl diff --git a/cups.dsw b/cups.dsw new file mode 100644 index 0000000000..28bdbaa895 --- /dev/null +++ b/cups.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cups"=.\cups\cups.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/cups.list b/cups.list new file mode 100644 index 0000000000..8be9f19a8c --- /dev/null +++ b/cups.list @@ -0,0 +1,320 @@ +# +# "$Id: cups.list 1682 2001-04-19 16:35:35Z mike $" +# +# ESP Package Manager (EPM) file list for the Common UNIX Printing +# System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# Product information +%product Common UNIX Printing System +%copyright 1993-2001 by Easy Software Products, All Rights Reserved. +%vendor Easy Software Products +%license LICENSE.txt +%readme README.txt +%version 1.1.7 +%incompat printpro + +# Server programs +%system all +# Server files +f 0555 root sys $SBINDIR/cupsd scheduler/cupsd + +d 0555 root sys $SERVERBIN - +d 0555 root sys $SERVERBIN/backend - +f 0555 root sys $SERVERBIN/backend/ipp backend/ipp +l 0555 root sys $SERVERBIN/backend/http ipp +f 0555 root sys $SERVERBIN/backend/lpd backend/lpd +f 0555 root sys $SERVERBIN/backend/parallel backend/parallel +f 0555 root sys $SERVERBIN/backend/serial backend/serial +f 0555 root sys $SERVERBIN/backend/socket backend/socket +f 0555 root sys $SERVERBIN/backend/usb backend/usb +d 0555 root sys $SERVERBIN/cgi-bin - +f 0555 root sys $SERVERBIN/cgi-bin/admin.cgi cgi-bin/admin.cgi +f 0555 root sys $SERVERBIN/cgi-bin/classes.cgi cgi-bin/classes.cgi +f 0555 root sys $SERVERBIN/cgi-bin/jobs.cgi cgi-bin/jobs.cgi +f 0555 root sys $SERVERBIN/cgi-bin/printers.cgi cgi-bin/printers.cgi +d 0555 root sys $SERVERBIN/daemon - +f 0555 root sys $SERVERBIN/daemon/cups-lpd scheduler/cups-lpd +f 0555 root sys $SERVERBIN/daemon/cups-polld scheduler/cups-polld +d 0555 root sys $SERVERBIN/filter - +f 0555 root sys $SERVERBIN/filter/pstoraster pstoraster/pstoraster +f 0555 root sys $SERVERBIN/filter/pdftops pdftops/pdftops +f 0555 root sys $SERVERBIN/filter/imagetops filter/imagetops +f 0555 root sys $SERVERBIN/filter/pstops filter/pstops +f 0555 root sys $SERVERBIN/filter/texttops filter/texttops +f 0555 root sys $SERVERBIN/filter/rastertoepson filter/rastertoepson +f 0555 root sys $SERVERBIN/filter/rastertohp filter/rastertohp +f 0555 root sys $SERVERBIN/filter/hpgltops filter/hpgltops +f 0555 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster + +# Admin commands +l 0555 root sys $BINDIR/disable $SBINDIR/accept +l 0555 root sys $BINDIR/enable $SBINDIR/accept +l 0555 root sys $LIBDIR/accept $SBINDIR/accept +l 0555 root sys $LIBDIR/lpadmin $SBINDIR/lpadmin +l 0555 root sys $LIBDIR/reject accept +f 0555 root sys $SBINDIR/accept systemv/accept +f 0555 root sys $SBINDIR/lpadmin systemv/lpadmin +f 0555 root sys $SBINDIR/lpc berkeley/lpc +f 0555 root sys $SBINDIR/lpinfo systemv/lpinfo +f 0555 root sys $SBINDIR/lpmove systemv/lpmove +l 0555 root sys $SBINDIR/reject accept + +%system irix +l 0555 root sys /usr/etc/lpc $SBINDIR/lpc +%system all + +# User commands +f 0555 root sys $BINDIR/cancel systemv/cancel +f 0555 root sys $BINDIR/lp systemv/lp +f 0555 root sys $BINDIR/lpoptions systemv/lpoptions +f 4555 root sys $BINDIR/lppasswd systemv/lppasswd +f 0555 root sys $BINDIR/lpq berkeley/lpq +f 0555 root sys $BINDIR/lpr berkeley/lpr +f 0555 root sys $BINDIR/lprm berkeley/lprm +f 0555 root sys $BINDIR/lpstat systemv/lpstat + +%system irix +l 0555 root sys /usr/bsd/lpq $BINDIR/lpq +l 0555 root sys /usr/bsd/lpr $BINDIR/lpr +l 0555 root sys /usr/bsd/lprm $BINDIR/lprm +%system all + +# DSOs +%system hpux +f 0555 root sys $LIBDIR/libcups.sl.2 cups/libcups.sl.2 +l 0555 root sys $LIBDIR/libcups.sl libcups.sl.2 +f 0555 root sys $LIBDIR/libcupsimage.sl.2 filter/libcupsimage.sl.2 +l 0555 root sys $LIBDIR/libcupsimage.sl libcupsimage.sl.2 +%system !hpux +f 0555 root sys $LIBDIR/libcups.so.2 cups/libcups.so.2 +l 0555 root sys $LIBDIR/libcups.so libcups.so.2 +f 0555 root sys $LIBDIR/libcupsimage.so.2 filter/libcupsimage.so.2 +l 0555 root sys $LIBDIR/libcupsimage.so libcupsimage.so.2 +%system all + +# Directories +d 0755 root sys $LOGDIR - +d 0700 lp sys $REQUESTS - +d 1700 lp sys $REQUESTS/tmp - + +# Data files +f 0444 root sys $LOCALEDIR/C/cups_C locale/C/cups_C +f 0444 root sys $LOCALEDIR/de/cups_de locale/de/cups_de +f 0444 root sys $LOCALEDIR/en/cups_en locale/en/cups_en +f 0444 root sys $LOCALEDIR/es/cups_es locale/es/cups_es +f 0444 root sys $LOCALEDIR/fr/cups_fr locale/fr/cups_fr +f 0444 root sys $LOCALEDIR/it/cups_it locale/it/cups_it + +d 0555 root sys $DATADIR - + +d 0555 root sys $DATADIR/banners - +f 0444 root sys $DATADIR/banners/classified data/classified +f 0444 root sys $DATADIR/banners/confidential data/confidential +f 0444 root sys $DATADIR/banners/secret data/secret +f 0444 root sys $DATADIR/banners/standard data/standard +f 0444 root sys $DATADIR/banners/topsecret data/topsecret +f 0444 root sys $DATADIR/banners/unclassified data/unclassified + +d 0555 root sys $DATADIR/charsets - +f 0444 root sys $DATADIR/charsets/windows-874 data/windows-874 +f 0444 root sys $DATADIR/charsets/windows-1250 data/windows-1250 +f 0444 root sys $DATADIR/charsets/windows-1251 data/windows-1251 +f 0444 root sys $DATADIR/charsets/windows-1252 data/windows-1252 +f 0444 root sys $DATADIR/charsets/windows-1253 data/windows-1253 +f 0444 root sys $DATADIR/charsets/windows-1254 data/windows-1254 +f 0444 root sys $DATADIR/charsets/windows-1255 data/windows-1255 +f 0444 root sys $DATADIR/charsets/windows-1256 data/windows-1256 +f 0444 root sys $DATADIR/charsets/windows-1257 data/windows-1257 +f 0444 root sys $DATADIR/charsets/windows-1258 data/windows-1258 +f 0444 root sys $DATADIR/charsets/iso-8859-1 data/iso-8859-1 +f 0444 root sys $DATADIR/charsets/iso-8859-14 data/iso-8859-14 +f 0444 root sys $DATADIR/charsets/iso-8859-15 data/iso-8859-15 +f 0444 root sys $DATADIR/charsets/iso-8859-2 data/iso-8859-2 +f 0444 root sys $DATADIR/charsets/iso-8859-3 data/iso-8859-3 +f 0444 root sys $DATADIR/charsets/iso-8859-4 data/iso-8859-4 +f 0444 root sys $DATADIR/charsets/iso-8859-5 data/iso-8859-5 +f 0444 root sys $DATADIR/charsets/iso-8859-6 data/iso-8859-6 +f 0444 root sys $DATADIR/charsets/iso-8859-7 data/iso-8859-7 +f 0444 root sys $DATADIR/charsets/iso-8859-8 data/iso-8859-8 +f 0444 root sys $DATADIR/charsets/iso-8859-9 data/iso-8859-9 +f 0444 root sys $DATADIR/charsets/utf-8 data/utf-8 + +d 0555 root sys $DATADIR/data - +f 0444 root sys $DATADIR/data/HPGLprolog data/HPGLprolog +f 0444 root sys $DATADIR/data/psglyphs data/psglyphs +f 0444 root sys $DATADIR/data/testprint.ps data/testprint.ps + +d 0555 root sys $DATADIR/fonts - +f 0444 root sys $DATADIR/fonts fonts/* + +d 0555 root sys $DATADIR/pstoraster - +f 0444 root sys $DATADIR/pstoraster/Fontmap pstoraster/Fontmap +f 0444 root sys $DATADIR/pstoraster pstoraster/gs*.ps + +d 0555 root sys $DATADIR/model - +f 0444 root sys $DATADIR/model ppd/*.ppd + +d 0555 root sys $DATADIR/templates - +f 0444 root sys $DATADIR/templates templates/*.tmpl + +# Config files +d 0555 root sys $SERVERROOT - +d 0711 root sys $SERVERROOT/certs - +d 0755 root sys $SERVERROOT/interfaces - +d 0755 root sys $SERVERROOT/ppd - +c 0644 root sys $SERVERROOT conf/*.conf +f 0644 root sys $SERVERROOT/mime.convs conf/mime.convs +f 0644 root sys $SERVERROOT/mime.types conf/mime.types + +%system linux +d 0555 root sys $PAMDIR - +c 0644 root sys $PAMDIR/cups data/cups.pam +c 0644 root sys $PAMDIR/cups.suse data/cups.suse +%install if test -f /lib/security/pam_unix.so; then +%install mv $PAMDIR/cups.suse $PAMDIR/cups +%install fi +%system all + +# Developer files +d 0555 root sys $INCLUDEDIR/cups - +f 0444 root sys $INCLUDEDIR/cups/cups.h cups/cups.h +f 0444 root sys $INCLUDEDIR/cups/http.h cups/http.h +f 0444 root sys $INCLUDEDIR/cups/image.h filter/image.h +f 0444 root sys $INCLUDEDIR/cups/ipp.h cups/ipp.h +f 0444 root sys $INCLUDEDIR/cups/language.h cups/language.h +f 0444 root sys $INCLUDEDIR/cups/md5.h cups/md5.h +f 0444 root sys $INCLUDEDIR/cups/ppd.h cups/ppd.h +f 0444 root sys $INCLUDEDIR/cups/raster.h filter/raster.h + +f 0444 root sys $LIBDIR/libcups.a cups/libcups.a + +# Documentation files +d 0555 root sys $DOCDIR - +f 0444 root sys $DOCDIR/cups.css doc/cups.css +f 0444 root sys $DOCDIR doc/*.html +f 0444 root sys $DOCDIR doc/*.pdf +d 0555 root sys $DOCDIR/images - +f 0444 root sys $DOCDIR/images doc/images/*.gif + +# Man pages +%system irix +d 0555 root sys $AMANDIR - +d 0555 root sys $AMANDIR/cat1 - +d 0555 root sys $MANDIR - +d 0555 root sys $MANDIR/cat1 - +d 0555 root sys $MANDIR/cat5 - + +f 0444 root sys $AMANDIR/cat1/accept.z man/accept.z +l 0444 root sys $AMANDIR/cat1/reject.z accept.z +f 0444 root sys $MANDIR/cat1/backend.z man/backend.z +f 0444 root sys $MANDIR/cat5/classes.conf.z man/classes.conf.z +f 0444 root sys $AMANDIR/cat1/cups-lpd.z man/cups-lpd.z +f 0444 root sys $AMANDIR/cat1/cups-polld.z man/cups-polld.z +f 0444 root sys $MANDIR/cat5/cupsd.conf.z man/cupsd.conf.z +f 0444 root sys $AMANDIR/cat1/cupsd.z man/cupsd.z +f 0444 root sys $AMANDIR/cat1/enable.z man/enable.z +l 0444 root sys $AMANDIR/cat1/disable.z enable.z +f 0444 root sys $MANDIR/cat1/filter.z man/filter.z +f 0444 root sys $AMANDIR/cat1/lpadmin.z man/lpadmin.z +f 0444 root sys $AMANDIR/cat1/lpc.z man/lpc.z +f 0444 root sys $AMANDIR/cat1/lpinfo.z man/lpinfo.z +f 0444 root sys $AMANDIR/cat1/lpmove.z man/lpmove.z +f 0444 root sys $MANDIR/cat1/lpoptions.z man/lpoptions.z +f 0444 root sys $MANDIR/cat1/lpq.z man/lpq.z +f 0444 root sys $MANDIR/cat1/lprm.z man/lprm.z +f 0444 root sys $MANDIR/cat1/lpr.z man/lpr.z +f 0444 root sys $MANDIR/cat1/lpstat.z man/lpstat.z +f 0444 root sys $MANDIR/cat1/lp.z man/lp.z +l 0444 root sys $MANDIR/cat1/cancel.z lp.z +f 0444 root sys $MANDIR/cat5/mime.convs.z man/mime.convs.z +f 0444 root sys $MANDIR/cat5/mime.types.z man/mime.types.z +f 0444 root sys $MANDIR/cat5/printers.conf.z man/printers.conf.z + +%system solaris hpux +d 0555 root sys $MANDIR/man1 - +d 0555 root sys $MANDIR/man5 - +d 0555 root sys $MANDIR/man1m - + +f 0444 root sys $MANDIR/man1m/accept.1m man/accept.man +l 0444 root sys $MANDIR/man1m/reject.1m accept.1m +f 0444 root sys $MANDIR/man1/backend.1 man/backend.man +f 0444 root sys $MANDIR/man1/classes.conf.5 man/classes.conf.man +f 0444 root sys $MANDIR/man1m/cups-lpd.1m man/cups-lpd.man +f 0444 root sys $MANDIR/man1m/cups-polld.1m man/cups-polld.man +f 0444 root sys $MANDIR/man1m/cupsd.1m man/cupsd.man +f 0444 root sys $MANDIR/man5/cupsd.conf.5 man/cupsd.conf.man +f 0444 root sys $MANDIR/man1m/enable.1m man/enable.man +l 0444 root sys $MANDIR/man1m/disable.1m enable.1m +f 0444 root sys $MANDIR/man1/filter.1 man/filter.man +f 0444 root sys $MANDIR/man1m/lpadmin.1m man/lpadmin.man +f 0444 root sys $MANDIR/man1m/lpc.1m man/lpc.man +f 0444 root sys $MANDIR/man1m/lpinfo.1m man/lpinfo.man +f 0444 root sys $MANDIR/man1m/lpmove.1m man/lpmove.man +f 0444 root sys $MANDIR/man1/lpoptions.1 man/lpoptions.man +f 0444 root sys $MANDIR/man1/lpq.1 man/lpq.man +f 0444 root sys $MANDIR/man1/lprm.1 man/lprm.man +f 0444 root sys $MANDIR/man1/lpr.1 man/lpr.man +f 0444 root sys $MANDIR/man1/lpstat.1 man/lpstat.man +f 0444 root sys $MANDIR/man1/lp.1 man/lp.man +l 0444 root sys $MANDIR/man1/cancel.1 lp.1 +f 0444 root sys $MANDIR/man5/mime.convs.5 man/mime.convs.man +f 0444 root sys $MANDIR/man5/mime.types.5 man/mime.types.man +f 0444 root sys $MANDIR/man5/printers.conf.5 man/printers.conf.man + +%system !irix !solaris !hpux +d 0555 root sys $MANDIR/man1 - +d 0555 root sys $MANDIR/man5 - +d 0555 root sys $MANDIR/man8 - + +f 0444 root sys $MANDIR/man8/accept.8 man/accept.man +l 0444 root sys $MANDIR/man8/reject.8 accept.8 +f 0444 root sys $MANDIR/man1/backend.1 man/backend.man +f 0444 root sys $MANDIR/man1/classes.conf.5 man/classes.conf.man +f 0444 root sys $MANDIR/man8/cups-lpd.8 man/cups-lpd.man +f 0444 root sys $MANDIR/man8/cups-polld.8 man/cups-polld.man +f 0444 root sys $MANDIR/man8/cupsd.8 man/cupsd.man +f 0444 root sys $MANDIR/man5/cupsd.conf.5 man/cupsd.conf.man +f 0444 root sys $MANDIR/man8/enable.8 man/enable.man +l 0444 root sys $MANDIR/man8/disable.8 enable.8 +f 0444 root sys $MANDIR/man1/filter.1 man/filter.man +f 0444 root sys $MANDIR/man8/lpadmin.8 man/lpadmin.man +f 0444 root sys $MANDIR/man8/lpc.8 man/lpc.man +f 0444 root sys $MANDIR/man8/lpinfo.8 man/lpinfo.man +f 0444 root sys $MANDIR/man8/lpmove.8 man/lpmove.man +f 0444 root sys $MANDIR/man1/lpoptions.1 man/lpoptions.man +f 0444 root sys $MANDIR/man1/lpq.1 man/lpq.man +f 0444 root sys $MANDIR/man1/lprm.1 man/lprm.man +f 0444 root sys $MANDIR/man1/lpr.1 man/lpr.man +f 0444 root sys $MANDIR/man1/lpstat.1 man/lpstat.man +f 0444 root sys $MANDIR/man1/lp.1 man/lp.man +l 0444 root sys $MANDIR/man1/cancel.1 lp.1 +f 0444 root sys $MANDIR/man5/mime.convs.5 man/mime.convs.man +f 0444 root sys $MANDIR/man5/mime.types.5 man/mime.types.man +f 0444 root sys $MANDIR/man5/printers.conf.5 man/printers.conf.man + +# Startup script +%system all +i 0555 root sys cups cups.sh + +# +# End of "$Id: cups.list 1682 2001-04-19 16:35:35Z mike $". +# diff --git a/cups.sh.in b/cups.sh.in new file mode 100755 index 0000000000..71e41ef0a6 --- /dev/null +++ b/cups.sh.in @@ -0,0 +1,143 @@ +#!/bin/sh +# +# "$Id$" +# +# Startup/shutdown script for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +#### OS-Dependent Information + +# +# Linux chkconfig stuff: +# +# chkconfig: 0235 99 00 +# description: Startup/shutdown script for the Common UNIX \ +# Printing System (CUPS). +# + +# +# NetBSD 1.5+ rcorder script lines. The format of the following two +# lines is very strict -- please don't add additional spaces! +# +# PROVIDE: cups +# REQUIRE: DAEMON +# + + +#### OS-Dependent Configuration +case "`uname`" in + IRIX*) + IS_ON=/sbin/chkconfig + ;; + + NetBSD*) + IS_ON=: + ;; + + *) + IS_ON=/bin/true + ;; +esac + +#### OS-Independent Stuff + +# +# The verbose flag controls the printing of the names of +# daemons as they are started. Currently always echos for +# all but IRIX, which can configure verbose bootup messages. +# + +if $IS_ON verbose; then + ECHO=echo +else + ECHO=: +fi + +# +# See if the CUPS server (cupsd) is running... +# + +case "`uname`" in + IRIX* | HP-UX* | SunOS*) + pid=`ps -e | awk '{print $1,$4}' | grep cupsd | awk '{print $1}'` + ;; + OSF1*) + pid=`ps -e | awk '{print $1,$5}' | grep cupsd | awk '{print $1}'` + ;; + Linux* | NetBSD*) + pid=`ps ax | awk '{print $1,$5}' | grep cupsd | awk '{print $1}'` + ;; + *) + pid="" + ;; +esac + +# +# Start or stop the CUPS server based upon the first argument to the script. +# + +case $1 in + start | restart | reload) + if $IS_ON cups; then + if test "$pid" != ""; then + kill -HUP $pid + else + prefix=@prefix@ + exec_prefix=@exec_prefix@ + @sbindir@/cupsd + fi + $ECHO "cups: scheduler ${1}ed." + else + $ECHO "cups: scheduler stopped." + fi + ;; + + stop) + if test "$pid" != ""; then + kill $pid + $ECHO "cups: scheduler stopped." + fi + ;; + + status) + if test "$pid" != ""; then + echo "cups: Scheduler is running." + else + echo "cups: Scheduler is not running." + fi + ;; + + *) + echo "Usage: cups {reload|restart|start|status|stop}" + exit 1 + ;; +esac + +# +# Exit with no errors. +# + +exit 0 + + +# +# End of "$Id$". +# diff --git a/cups.spec b/cups.spec new file mode 100644 index 0000000000..1e036223e8 --- /dev/null +++ b/cups.spec @@ -0,0 +1,179 @@ +# +# "$Id: cups.spec 1615 2001-03-06 18:37:49Z mike $" +# +# RPM "spec" file for the Common UNIX Printing System (CUPS). +# +# Original version by Jason McMullan . +# +# Copyright 1999-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +Summary: Common Unix Printing System +Name: cups +Version: 1.1.7 +Release: 0 +Copyright: GPL +Group: System Environment/Daemons +Source: ftp://ftp.easysw.com/pub/cups/%{version}/cups-%{version}-source.tar.gz +Url: http://www.cups.org +Packager: Michael Sweet +Vendor: Easy Software Products +# use buildroot so as not to disturb the version already installed +BuildRoot: /var/tmp/%{name}-root +Conflicts: lpr, LPRng + +%package devel +Summary: Common Unix Printing System - development environment +Group: Development/Libraries + +%description +The Common UNIX Printing System provides a portable printing layer for +UNIX® operating systems. It has been developed by Easy Software Products +to promote a standard printing solution for all UNIX vendors and users. +CUPS provides the System V and Berkeley command-line interfaces. + +%description devel +The Common UNIX Printing System provides a portable printing layer for +UNIX® operating systems. This is the development package for creating +additional printer drivers, and other CUPS services. + +%prep +%setup + +%build +./configure + +# If we got this far, all prerequisite libraries must be here. +make + +%install +# these lines just make sure the directory structure in the +# RPM_BUILD_ROOT exists +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/rc0.d +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/rc3.d +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/rc5.d + +make prefix=$RPM_BUILD_ROOT \ + exec_prefix=$RPM_BUILD_ROOT/usr \ + AMANDIR=$RPM_BUILD_ROOT/usr/man \ + BINDIR=$RPM_BUILD_ROOT/usr/bin \ + DATADIR=$RPM_BUILD_ROOT/usr/share/cups \ + DOCDIR=$RPM_BUILD_ROOT/usr/share/doc/cups \ + INCLUDEDIR=$RPM_BUILD_ROOT/usr/include \ + LIBDIR=$RPM_BUILD_ROOT/usr/lib \ + LOCALEDIR=$RPM_BUILD_ROOT/usr/share/locale \ + MANDIR=$RPM_BUILD_ROOT/usr/man \ + PAMDIR=$RPM_BUILD_ROOT/etc/pam.d \ + REQUESTS=$RPM_BUILD_ROOT/var/spool/cups \ + SBINDIR=$RPM_BUILD_ROOT/usr/sbin \ + SERVERBIN=$RPM_BUILD_ROOT/usr/lib/cups \ + SERVERROOT=$RPM_BUILD_ROOT/etc/cups \ + install + +%post +if test -x /sbin/chkconfig; then + /sbin/chkconfig --add cups + /sbin/chkconfig cups on +fi + +# these lines automatically start cupsd after installation; commented out +# by request... +#if test -f /sbin/init.d/cups; then +# /sbin/init.d/cups start +#fi +#if test -f /etc/rc.d/init.d/cups; then +# /etc/rc.d/init.d/cups start +#fi +#if test -f /etc/init.d/cups; then +# /etc/init.d/cups start +#fi + +%preun +if test -f /sbin/init.d/cups; then + /sbin/init.d/cups stop +fi +if test -f /etc/rc.d/init.d/cups; then + /etc/rc.d/init.d/cups stop +fi +if test -f /etc/init.d/cups; then + /etc/init.d/cups stop +fi + +if test -x /sbin/chkconfig; then + /sbin/chkconfig --del cups +fi + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%dir /etc/cups +%config(noreplace) /etc/cups/*.conf +%dir /etc/cups/certs +%dir /etc/cups/interfaces +/etc/cups/mime.types +/etc/cups/mime.convs +%dir /etc/cups/ppd +%dir /etc/pam.d +/etc/pam.d/* + +# RC dirs are a pain under Linux... Uncomment the appropriate ones if you +# don't use Red Hat or Mandrake... + +/etc/rc.d/init.d/* +/etc/rc.d/rc0.d/* +/etc/rc.d/rc3.d/* +/etc/rc.d/rc5.d/* + +#/etc/init.d/* +#/etc/rc0.d/* +#/etc/rc3.d/* +#/etc/rc5.d/* + +#/sbin/rc.d/* +#/sbin/rc.d/rc0.d/* +#/sbin/rc.d/rc3.d/* +#/sbin/rc.d/rc5.d/* + +/usr/bin/* +/usr/lib/*.so* +%dir /usr/lib/cups +/usr/lib/cups/* +/usr/man/* +/usr/sbin/* +%dir /usr/share/cups +/usr/share/cups/* +%dir /usr/share/doc/cups +/usr/share/doc/cups/* +%dir /usr/share/locale +/usr/share/locale/* +%attr(0700,lp,root) %dir /var/spool/cups +%attr(1700,lp,root) %dir /var/spool/cups/tmp + +%files devel +%dir /usr/include/cups +/usr/include/cups/* +/usr/lib/*.a + +# +# End of "$Id: cups.spec 1615 2001-03-06 18:37:49Z mike $". +# diff --git a/cups/Makefile b/cups/Makefile new file mode 100644 index 0000000000..ba23604f67 --- /dev/null +++ b/cups/Makefile @@ -0,0 +1,170 @@ +# +# "$Id$" +# +# Support library Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2001 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Object files... +# + +LIBOBJS = dest.o emit.o encode.o http.o ipp.o language.o mark.o md5.o \ + md5passwd.o options.o page.o ppd.o snprintf.o string.o \ + tempfile.o usersys.o util.o +OBJS = $(LIBOBJS) testhttp.o testppd.o + + +# +# Header files to install... +# + +HEADERS = cups.h http.h ipp.h language.h md5.h ppd.h + + +# +# Targets in this directory... +# + +TARGETS = $(LIBCUPS) libcups.a + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Remove object and target files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) `basename $(LIBCUPS) .2` + + +# +# Install object and target files... +# + +install: all + -$(MKDIR) $(INCLUDEDIR)/cups + $(CHMOD) ugo+rx $(INCLUDEDIR) + $(CHMOD) ugo+rx $(INCLUDEDIR)/cups + $(INSTALL_DATA) $(HEADERS) $(INCLUDEDIR)/cups + -$(MKDIR) $(LIBDIR) + $(CHMOD) ugo+rx $(LIBDIR) + $(INSTALL_LIB) $(LIBCUPS) $(LIBDIR) + if test $(LIBCUPS) != "libcups.a" -a $(LIBCUPS) != "libcups.la"; then \ + $(INSTALL_LIB) libcups.a $(LIBDIR); \ + $(RM) $(LIBDIR)/`basename $(LIBCUPS) .2`; \ + $(LN) $(LIBCUPS) $(LIBDIR)/`basename $(LIBCUPS) .2`; \ + fi + + +# +# libcups.so.2, libcups.sl.1 +# + +libcups.so.2 libcups.sl.2: $(LIBOBJS) ../Makedefs + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS) $(SSLLIBS) + $(RM) `basename $@ .2` + $(LN) $@ `basename $@ .2` + + +# +# libcups.la +# + +libcups.la: $(LIBOBJS) ../Makedefs + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \ + -version-info 2:3 $(SSLLIBS) + + +# +# libcups.a +# + +libcups.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + + +# +# cups_C.h - the default POSIX locale that is compiled in. +# + +cups_C.h: ../locale/C/cups_C + echo Generating $@... + $(RM) cups_C.h + $(AWK) '{print "\"" $$0 "\","}' < ../locale/C/cups_C > cups_C.h + +dest.o: cups.h http.h ipp.h language.h string.h +emit.o: ppd.h +encode.o: cups.h ipp.h string.h +http.o: http.h ipp.h md5.h string.h +ipp.o: http.h ipp.h string.h language.h +language.o: cups_C.h language.h string.h +mark.o: ppd.h +md5.o: md5.h +options.o: cups.h +page.o: ppd.h +ppd.o: language.h ppd.h +snprintf.o: string.h +string.o: string.h +tempfile.o: cups.h string.h +usersys.o: cups.h +util.o: cups.h http.h ipp.h + + +# +# testhttp (dependency on static CUPS library is intentional) +# + +testhttp: testhttp.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testhttp.o libcups.a $(NETLIBS) $(SSLLIBS) + +testhttp.o: http.h + + +# +# testppd (dependency on static CUPS library is intentional) +# + +testppd: testppd.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testppd.o libcups.a $(NETLIBS) + +testppd.o: ppd.h + +$(OBJS): ../Makedefs ../config.h + + +# +# End of "$Id$". +# diff --git a/cups/cups.dsp b/cups/cups.dsp new file mode 100644 index 0000000000..8822fdbe02 --- /dev/null +++ b/cups/cups.dsp @@ -0,0 +1,188 @@ +# Microsoft Developer Studio Project File - Name="cups" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=cups - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cups.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cups.mak" CFG="cups - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cups - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "cups - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cups - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\visualc" /I ".." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"cups.lib" + +!ELSEIF "$(CFG)" == "cups - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\visualc" /I ".." /I "../visualc" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"cupsd.lib" + +!ENDIF + +# Begin Target + +# Name "cups - Win32 Release" +# Name "cups - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\dest.c +# End Source File +# Begin Source File + +SOURCE=.\emit.c +# End Source File +# Begin Source File + +SOURCE=.\http.c +# End Source File +# Begin Source File + +SOURCE=.\ipp.c +# End Source File +# Begin Source File + +SOURCE=.\language.c +# End Source File +# Begin Source File + +SOURCE=.\mark.c +# End Source File +# Begin Source File + +SOURCE=.\md5.c +# End Source File +# Begin Source File + +SOURCE=.\md5passwd.c +# End Source File +# Begin Source File + +SOURCE=.\options.c +# End Source File +# Begin Source File + +SOURCE=.\page.c +# End Source File +# Begin Source File + +SOURCE=.\ppd.c +# End Source File +# Begin Source File + +SOURCE=.\snprintf.c +# End Source File +# Begin Source File + +SOURCE=.\string.c +# End Source File +# Begin Source File + +SOURCE=.\usersys.c +# End Source File +# Begin Source File + +SOURCE=.\util.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\cups.h +# End Source File +# Begin Source File + +SOURCE=.\cups_C.h +# End Source File +# Begin Source File + +SOURCE=.\debug.h +# End Source File +# Begin Source File + +SOURCE=.\http.h +# End Source File +# Begin Source File + +SOURCE=.\ipp.h +# End Source File +# Begin Source File + +SOURCE=.\language.h +# End Source File +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# Begin Source File + +SOURCE=.\ppd.h +# End Source File +# Begin Source File + +SOURCE=.\string.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/cups.h b/cups/cups.h new file mode 100644 index 0000000000..4b31f959a8 --- /dev/null +++ b/cups/cups.h @@ -0,0 +1,175 @@ +/* + * "$Id$" + * + * API definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_CUPS_H_ +# define _CUPS_CUPS_H_ + +/* + * Include necessary headers... + */ + +# include "ipp.h" +# include "ppd.h" + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Constants... + */ + +# define CUPS_VERSION 1.0103 +# define CUPS_DATE_ANY -1 + + +/* + * Types and structures... + */ + +typedef unsigned cups_ptype_t; /**** Printer Type/Capability Bits ****/ +enum /* Not a typedef'd enum so we can OR */ +{ + CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */ + CUPS_PRINTER_CLASS = 0x0001, /* Printer class */ + CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */ + CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */ + CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */ + CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */ + CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */ + CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */ + CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */ + CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */ + CUPS_PRINTER_COVER = 0x0200, /* Can cover output */ + CUPS_PRINTER_BIND = 0x0400, /* Can bind output */ + CUPS_PRINTER_SORT = 0x0800, /* Can sort output */ + CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */ + CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */ + CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */ + CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */ + CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */ + CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */ + CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */ +}; + +typedef struct /**** Printer Options ****/ +{ + char *name; /* Name of option */ + char *value; /* Value of option */ +} cups_option_t; + +typedef struct /**** Destination ****/ +{ + char *name, /* Printer or class name */ + *instance; /* Local instance name or NULL */ + int is_default; /* Is this printer the default? */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ +} cups_dest_t; + +typedef struct /**** Job ****/ +{ + int id; /* The job ID */ + char *dest, /* Printer or class name */ + *title, /* Title/job name */ + *user, /* User the submitted the job */ + *format; /* Document format */ + ipp_jstate_t state; /* Job state */ + int size, /* Size in kilobytes */ + priority; /* Priority (1-100) */ + time_t completed_time, /* Time the job was completed */ + creation_time, /* Time the job was created */ + processing_time; /* Time the job was processed */ +} cups_job_t; + + +/* + * Functions... + */ + +extern int cupsCancelJob(const char *printer, int job); +#define cupsDoRequest(http,request,resource) cupsDoFileRequest((http),(request),(resource),NULL) +extern ipp_t *cupsDoFileRequest(http_t *http, ipp_t *request, + const char *resource, const char *filename); +extern http_encryption_t cupsEncryption(void); +extern void cupsFreeJobs(int num_jobs, cups_job_t *jobs); +extern int cupsGetClasses(char ***classes); +extern const char *cupsGetDefault(void); +extern int cupsGetJobs(cups_job_t **jobs, const char *dest, + int myjobs, int completed); +extern const char *cupsGetPPD(const char *printer); +extern int cupsGetPrinters(char ***printers); +extern ipp_status_t cupsLastError(void); +extern int cupsPrintFile(const char *printer, const char *filename, + const char *title, int num_options, + cups_option_t *options); +extern int cupsPrintFiles(const char *printer, int num_files, + const char **files, const char *title, + int num_options, cups_option_t *options); +extern char *cupsTempFile(char *filename, int len); +extern int cupsTempFd(char *filename, int len); + +extern int cupsAddDest(const char *name, const char *instance, + int num_dests, cups_dest_t **dests); +extern void cupsFreeDests(int num_dests, cups_dest_t *dests); +extern cups_dest_t *cupsGetDest(const char *name, const char *instance, + int num_dests, cups_dest_t *dests); +extern int cupsGetDests(cups_dest_t **dests); +extern void cupsSetDests(int num_dests, cups_dest_t *dests); + +extern int cupsAddOption(const char *name, const char *value, + int num_options, cups_option_t **options); +extern void cupsEncodeOptions(ipp_t *ipp, int num_options, + cups_option_t *options); +extern void cupsFreeOptions(int num_options, cups_option_t *options); +extern const char *cupsGetOption(const char *name, int num_options, + cups_option_t *options); +extern int cupsParseOptions(const char *arg, int num_options, + cups_option_t **options); +extern int cupsMarkOptions(ppd_file_t *ppd, int num_options, + cups_option_t *options); + +extern const char *cupsGetPassword(const char *prompt); +extern const char *cupsServer(void); +extern void cupsSetEncryption(http_encryption_t e); +extern void cupsSetPasswordCB(const char *(*cb)(const char *)); +extern void cupsSetServer(const char *server); +extern void cupsSetUser(const char *user); +extern const char *cupsUser(void); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_CUPS_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/cups_C.h b/cups/cups_C.h new file mode 100644 index 0000000000..e0b12d155e --- /dev/null +++ b/cups/cups_C.h @@ -0,0 +1,133 @@ +"iso-8859-1", +"OK", +"Cancel", +"Help", +"Quit", +"Close", +"Yes", +"No", +"On", +"Off", +"Save", +"Discard", +"Default", +"Options", +"More Info", +"Black", +"Color", +"Cyan", +"Magenta", +"Yellow", +"Copyright 1993-2001 by Easy Software Products, All Rights Reserved.", +"General", +"Printer", +"Image", +"HP-GL/2", +"Extra", +"Document", +"Other", +"Print Pages: ", +"Entire Document", +"Page Range:", +"Reverse Order: ", +"Page Format: ", +" 1-Up", +" 2-Up", +" 4-Up", +"Image Scaling: ", +"Use Natural Image Size", +"Zoom by Percent", +"Zoom by PPI", +"Mirror Image: ", +"Color Saturation: ", +"Color Hue: ", +"Fit to Page: ", +"Shading: ", +"Pen Width: ", +"Gamma Correction: ", +"Brightness: ", +"Add", +"Delete", +"Modify", +"Printer URI", +"Printer Name", +"Printer Location", +"Printer Info", +"Printer Make and Model", +"Device URI", +"Formatting Page", +"Printing Page", +"Initializing Printer", +"Printer State", +"Accepting Jobs", +"Not Accepting Jobs", +"Print Jobs", +"Class", +"Local", +"Remote", +"Duplexing", +"Stapling", +"Fast Copies", +"Collated Copies", +"Hole Punching", +"Covering", +"Binding", +"Sorting", +"Small (up to 9.5x14in)", +"Medium (9.5x14in to 13x19in)", +"Large (13x19in and larger)", +"Custom Size", +"Idle", +"Processing", +"Stopped", +"All", +"Odd", +"Even", +"Darker Lighter", +"Media Size", +"Media Type", +"Media Source", +"Orientation: ", +"Portrait", +"Landscape", +"Job State", +"Job Name", +"User Name", +"Priority", +"Copies", +"File Size", +"Pending", +"Output Mode", +"Resolution", +"Text", +"Pretty Print", +"Margins", +"Left", +"Right", +"Bottom", +"Top", +"Filename(s)", +"Print", +"400 Your browser sent a request that this server could not understand.", +"This server could not verify that you are authorized to access the resource.", +"You must pay to access this server.", +"You don't have permission to access the resource on this server.", +"The requested resource was not found on this server.", +"The requested method is not allowed with the resource.", +"An appropriate representation for the resource was not found on this server.", +"You don't have permission to use this server as a proxy host.", +"The request has taken too long to complete and has been aborted.", +"The requested resource has more than one value.", +"The requested resource is gone and has not been replaced.", +"The requested method requires a valid Content-Length.", +"The precondition on the request evaluated to false.", +"The request is too large for this server to process.", +"The request URI is too large for this server to process.", +"The request format is not understood by this server.", +"426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.", +"500 The server has detected an unrecoverable error and cannot process your request.", +"The requested method is not implemented by this server.", +"The proxy server received an invalid response from an upstream server.", +"The requested resource is currently unavailable on this server.", +"The proxy server has taken too long to respond to this server.", +"This server does not support the HTTP version required by your browser.", diff --git a/cups/debug.h b/cups/debug.h new file mode 100644 index 0000000000..6935afac1b --- /dev/null +++ b/cups/debug.h @@ -0,0 +1,57 @@ +/* + * "$Id$" + * + * Debugging macros for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_DEBUG_H_ +# define _CUPS_DEBUG_H_ + +/* + * Include necessary headers... + */ + +# include + +/* + * The debug macros are used if you compile with DEBUG defined. + * + * Usage: + * + * DEBUG_puts("string") + * DEBUG_printf(("format string", arg, arg, ...)); + * + * Note the extra parenthesis around the DEBUG_printf macro... + */ + +# ifdef DEBUG +# define DEBUG_puts(x) puts(x) +# define DEBUG_printf(x) printf x +# else +# define DEBUG_puts(x) +# define DEBUG_printf(x) +# endif /* DEBUG */ + +#endif /* !_CUPS_DEBUG_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/dest.c b/cups/dest.c new file mode 100644 index 0000000000..dee2c2e286 --- /dev/null +++ b/cups/dest.c @@ -0,0 +1,546 @@ +/* + * "$Id$" + * + * User-defined destination (and option) support for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsAddDest() - Add a destination to the list of destinations. + * cupsFreeDests() - Free the memory used by the list of destinations. + * cupsGetDest() - Get the named destination from the list. + * cupsGetDests() - Get the list of destinations. + * cupsSetDests() - Set the list of destinations. + * cups_get_dests() - Get destinations from a file. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" +#include +#include + + +/* + * Local functions... + */ + +static int cups_get_dests(const char *filename, int num_dests, + cups_dest_t **dests); + + +/* + * 'cupsAddDest()' - Add a destination to the list of destinations. + */ + +int /* O - New number of destinations */ +cupsAddDest(const char *name, /* I - Name of destination */ + const char *instance, /* I - Instance of destination */ + int num_dests, /* I - Number of destinations */ + cups_dest_t **dests) /* IO - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Destination pointer */ + + + if (name == NULL || dests == NULL) + return (0); + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) + return (num_dests); + + /* + * Add new destination... + */ + + if (num_dests == 0) + dest = malloc(sizeof(cups_dest_t)); + else + dest = realloc(*dests, sizeof(cups_dest_t) * (num_dests + 1)); + + if (dest == NULL) + return (num_dests); + + *dests = dest; + + for (i = num_dests; i > 0; i --, dest ++) + if (strcasecmp(name, dest->name) < 0) + break; + else if (strcasecmp(name, dest->name) == 0 && + instance != NULL && dest->instance != NULL && + strcasecmp(instance, dest->instance) < 0) + break; + + if (i > 0) + memmove(dest + 1, dest, i * sizeof(cups_dest_t)); + + dest->name = strdup(name); + dest->is_default = 0; + dest->num_options = 0; + dest->options = (cups_option_t *)0; + + if (instance == NULL) + dest->instance = NULL; + else + dest->instance = strdup(instance); + + return (num_dests + 1); +} + + +/* + * 'cupsFreeDests()' - Free the memory used by the list of destinations. + */ + +void +cupsFreeDests(int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Current destination */ + + + if (num_dests == 0 || dests == NULL) + return; + + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + { + free(dest->name); + + if (dest->instance) + free(dest->instance); + + cupsFreeOptions(dest->num_options, dest->options); + } + + free(dests); +} + + +/* + * 'cupsGetDest()' - Get the named destination from the list. + */ + +cups_dest_t * /* O - Destination pointer or NULL */ +cupsGetDest(const char *name, /* I - Name of destination */ + const char *instance, /* I - Instance of destination */ + int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int comp; /* Result of comparison */ + + + if (num_dests == 0 || dests == NULL) + return (NULL); + + if (name == NULL) + { + /* + * NULL name for default printer. + */ + + while (num_dests > 0) + { + if (dests->is_default) + return (dests); + + num_dests --; + dests ++; + } + } + else + { + /* + * Lookup name and optionally the instance... + */ + + while (num_dests > 0) + { + if ((comp = strcasecmp(name, dests->name)) < 0) + return (NULL); + else if (comp == 0) + { + if ((instance == NULL && dests->instance == NULL) || + (instance != NULL && dests->instance != NULL && + strcasecmp(instance, dests->instance) == 0)) + return (dests); + } + + num_dests --; + dests ++; + } + } + + return (NULL); +} + + +/* + * 'cupsGetDests()' - Get the list of destinations. + */ + +int /* O - Number of destinations */ +cupsGetDests(cups_dest_t **dests) /* O - Destinations */ +{ + int i; /* Looping var */ + int num_dests; /* Number of destinations */ + int count; /* Number of printers/classes */ + char **names; /* Printer/class names */ + cups_dest_t *dest; /* Destination pointer */ + const char *home; /* HOME environment variable */ + char filename[1024]; /* Local ~/.lpoptions file */ + const char *defprinter; /* Default printer */ + char name[1024], /* Copy of printer name */ + *instance; /* Pointer to instance name */ + + + /* + * Initialize destination array... + */ + + num_dests = 0; + *dests = (cups_dest_t *)0; + + /* + * Grab all available printers... + */ + + if ((count = cupsGetPrinters(&names)) > 0) + { + for (i = 0; i < count; i ++) + { + num_dests = cupsAddDest(names[i], NULL, num_dests, dests); + free(names[i]); + } + + free(names); + } + + /* + * Grab all available classes... + */ + + if ((count = cupsGetClasses(&names)) > 0) + { + for (i = 0; i < count; i ++) + { + num_dests = cupsAddDest(names[i], NULL, num_dests, dests); + free(names[i]); + } + + free(names); + } + + /* + * Grab the default destination... + */ + + if ((defprinter = cupsGetDefault()) != NULL) + { + /* + * Grab printer and instance name... + */ + + strncpy(name, defprinter, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + + if ((instance = strchr(name, '/')) != NULL) + *instance++ = '\0'; + + /* + * Lookup the printer and instance and make it the default... + */ + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) + dest->is_default = 1; + } + + /* + * Load the /etc/cups/lpoptions and ~/.lpoptions files... + */ + + if ((home = getenv("CUPS_SERVERROOT")) != NULL) + { + snprintf(filename, sizeof(filename), "%s/lpoptions", home); + num_dests = cups_get_dests(filename, num_dests, dests); + } + else + num_dests = cups_get_dests(CUPS_SERVERROOT "/lpoptions", num_dests, dests); + + if ((home = getenv("HOME")) != NULL) + { + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + num_dests = cups_get_dests(filename, num_dests, dests); + } + + /* + * Return the number of destinations... + */ + + return (num_dests); +} + + +/* + * 'cupsSetDests()' - Set the list of destinations. + */ + +void +cupsSetDests(int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int i, j; /* Looping vars */ + cups_dest_t *dest; /* Current destination */ + cups_option_t *option; /* Current option */ + FILE *fp; /* File pointer */ + const char *home; /* HOME environment variable */ + char filename[1024]; /* lpoptions file */ + + + /* + * Figure out which file to write to... + */ + +#ifdef WIN32 + if ((home = getenv("CUPS_SERVERROOT")) == NULL) + home = CUPS_SERVERROOT; + + snprintf(filename, sizeof(filename), "%s/lpoptions", home); +#else + if (getuid() == 0) + { + if ((home = getenv("CUPS_SERVERROOT")) == NULL) + home = CUPS_SERVERROOT; + + snprintf(filename, sizeof(filename), "%s/lpoptions", home); + } + else if ((home = getenv("HOME")) != NULL) + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + else + return; +#endif /* WIN32 */ + + /* + * Try to open the file... + */ + + if ((fp = fopen(filename, "w")) == NULL) + return; + + /* + * Write each printer; each line looks like: + * + * Dest name[/instance] options + * Default name[/instance] options + */ + + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + if (dest->instance != NULL || dest->num_options != 0 || dest->is_default) + { + fprintf(fp, "%s %s", dest->is_default ? "Default" : "Dest", + dest->name); + if (dest->instance) + fprintf(fp, "/%s", dest->instance); + + for (j = dest->num_options, option = dest->options; j > 0; j --, option ++) + if (option->value[0]) + { + if (strchr(option->value, ' ') != NULL) + fprintf(fp, " %s=\"%s\"", option->name, option->value); + else + fprintf(fp, " %s=%s", option->name, option->value); + } + else + fprintf(fp, " %s", option->name); + + fputs("\n", fp); + } + + /* + * Close the file and return... + */ + + fclose(fp); +} + + +/* + * 'cups_get_dests()' - Get destinations from a file. + */ + +static int /* O - Number of destinations */ +cups_get_dests(const char *filename, /* I - File to read from */ + int num_dests, /* I - Number of destinations */ + cups_dest_t **dests) /* IO - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Current destination */ + FILE *fp; /* File pointer */ + char line[8192], /* Line from file */ + *lineptr, /* Pointer into line */ + *name, /* Name of destination/option */ + *instance; /* Instance of destination */ + const char *printer; /* PRINTER or LPDEST */ + + + /* + * Check environment variables... + */ + + if ((printer = getenv("LPDEST")) == NULL) + if ((printer = getenv("PRINTER")) != NULL) + if (strcmp(printer, "lp") == 0) + printer = NULL; + + /* + * Try to open the file... + */ + + if ((fp = fopen(filename, "r")) == NULL) + return (num_dests); + + /* + * Read each printer; each line looks like: + * + * Dest name[/instance] options + * Default name[/instance] options + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * See what type of line it is... + */ + + if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4])) + lineptr = line + 4; + else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7])) + lineptr = line + 7; + else + continue; + + /* + * Skip leading whitespace... + */ + + while (isspace(*lineptr)) + lineptr ++; + + if (!*lineptr) + continue; + + name = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr) && *lineptr && *lineptr != '/') + lineptr ++; + + if (!*lineptr) + continue; + + if (*lineptr == '/') + { + /* + * Found an instance... + */ + + *lineptr++ = '\0'; + instance = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + } + else + instance = NULL; + + *lineptr++ = '\0'; + + /* + * Add the destination... + */ + + num_dests = cupsAddDest(name, instance, num_dests, dests); + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) + { + /* + * Out of memory! + */ + + fclose(fp); + return (num_dests); + } + + /* + * Add options until we hit the end of the line... + */ + + if (dest->num_options) + { + /* + * Free old options... + */ + + cupsFreeOptions(dest->num_options, dest->options); + + dest->num_options = 0; + dest->options = (cups_option_t *)0; + } + + dest->num_options = cupsParseOptions(lineptr, dest->num_options, + &(dest->options)); + + /* + * Set this as default if needed... + */ + + if (strncasecmp(line, "default", 7) == 0 && printer == NULL) + { + for (i = 0; i < num_dests; i ++) + (*dests)[i].is_default = 0; + + dest->is_default = 1; + } + } + + /* + * Close the file and return... + */ + + fclose(fp); + + return (num_dests); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/emit.c b/cups/emit.c new file mode 100644 index 0000000000..ad0dc542da --- /dev/null +++ b/cups/emit.c @@ -0,0 +1,410 @@ +/* + * "$Id$" + * + * PPD code emission routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdCollect() - Collect all marked options that reside in the specified + * ppdEmit() - Emit code for marked options to a file. + * ppdEmitFd() - Emit code for marked options to a file. + * ppdEmitJCL() - Emit code for JCL options to a file. + * ppd_sort() - Sort options by ordering numbers... + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include +#include "string.h" + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2); + + +/* + * 'ppdCollect()' - Collect all marked options that reside in the specified + * section. + */ + +int /* O - Number of options marked */ +ppdCollect(ppd_file_t *ppd, /* I - PPD file data */ + ppd_section_t section, /* I - Section to collect */ + ppd_choice_t ***choices) /* O - Pointers to choices */ +{ + int i, j, k, m; /* Looping vars */ + ppd_group_t *g, /* Current group */ + *sg; /* Current sub-group */ + ppd_option_t *o; /* Current option */ + ppd_choice_t *c; /* Current choice */ + int count; /* Number of choices collected */ + ppd_choice_t **collect; /* Collected choices */ + + + if (ppd == NULL) + return (0); + + /* + * Allocate memory for up to 1000 selected choices... + */ + + count = 0; + collect = calloc(sizeof(ppd_choice_t *), 1000); + + /* + * Loop through all options and add choices as needed... + */ + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o = g->options; j > 0; j --, o ++) + if (o->section == section) + for (k = o->num_choices, c = o->choices; k > 0; k --, c ++) + if (c->marked && count < 1000) + { + collect[count] = c; + count ++; + } + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o = sg->options; k > 0; k --, o ++) + if (o->section == section) + for (m = o->num_choices, c = o->choices; m > 0; m --, c ++) + if (c->marked && count < 1000) + { + collect[count] = c; + count ++; + } + } + + /* + * If we have more than 1 marked choice, sort them... + */ + + if (count > 1) + qsort(collect, count, sizeof(ppd_choice_t *), + (int (*)(const void *, const void *))ppd_sort); + + /* + * Return the array and number of choices; if 0, free the array since + * it isn't needed. + */ + + if (count > 0) + { + *choices = collect; + return (count); + } + else + { + *choices = NULL; + free(collect); + return (0); + } +} + + +/* + * 'ppdEmit()' - Emit code for marked options to a file. + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmit(ppd_file_t *ppd, /* I - PPD file record */ + FILE *fp, /* I - File to write to */ + ppd_section_t section) /* I - Section to write */ +{ + int i, /* Looping var */ + count; /* Number of choices */ + ppd_choice_t **choices; /* Choices */ + ppd_size_t *size; /* Custom page size */ + + + if ((count = ppdCollect(ppd, section, &choices)) == 0) + return (0); + + for (i = 0; i < count; i ++) + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + /* + * Send wrapper commands to prevent printer errors for unsupported + * options... + */ + + if (fputs("[{\n", fp) < 0) + { + free(choices); + return (-1); + } + + /* + * Send DSC comments with option... + */ + + if (fprintf(fp, "%%%%BeginFeature: %s %s\n", + ((ppd_option_t *)choices[i]->option)->keyword, + choices[i]->choice) < 0) + { + free(choices); + return (-1); + } + + if (strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 && + strcasecmp(choices[i]->choice, "Custom") == 0) + { + /* + * Variable size; write out standard size options (this should + * eventually be changed to use the parameter positions defined + * in the PPD file...) + */ + + size = ppdPageSize(ppd, "Custom"); + fprintf(fp, "%.0f %.0f 0 0 0\n", size->width, size->length); + + if (choices[i]->code == NULL) + { + /* + * This can happen with certain buggy PPD files that don't include + * a CustomPageSize command sequence... We just use a generic + * Level 2 command sequence... + */ + + fputs("pop pop pop\n", fp); + fputs("<>setpagedevice\n", fp); + } + } + + if (choices[i]->code != NULL && choices[i]->code[0] != '\0') + { + if (fputs(choices[i]->code, fp) < 0) + { + free(choices); + return (-1); + } + + if (choices[i]->code[strlen(choices[i]->code) - 1] != '\n') + putc('\n', fp); + } + + if (fputs("%%EndFeature\n", fp) < 0) + { + free(choices); + return (-1); + } + + if (fputs("} stopped cleartomark\n", fp) < 0) + { + free(choices); + return (-1); + } + } + else if (fputs(choices[i]->code, fp) < 0) + { + free(choices); + return (-1); + } + + free(choices); + return (0); +} + + +/* + * 'ppdEmitFd()' - Emit code for marked options to a file. + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */ + int fd, /* I - File to write to */ + ppd_section_t section) /* I - Section to write */ +{ + int i, /* Looping var */ + count; /* Number of choices */ + ppd_choice_t **choices; /* Choices */ + char buf[1024]; /* Output buffer for feature */ + + + if ((count = ppdCollect(ppd, section, &choices)) == 0) + return (0); + + for (i = 0; i < count; i ++) + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + /* + * Send wrapper commands to prevent printer errors for unsupported + * options... + */ + + if (write(fd, "[{\n", 3) < 1) + { + free(choices); + return (-1); + } + + /* + * Send DSC comments with option... + */ + + snprintf(buf, sizeof(buf), "%%%%BeginFeature: %s %s\n", + ((ppd_option_t *)choices[i]->option)->keyword, + choices[i]->choice); + + if (write(fd, buf, strlen(buf)) < 1) + { + free(choices); + return (-1); + } + + if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) + { + free(choices); + return (-1); + } + + if (write(fd, "%%EndFeature\n", 13) < 1) + { + free(choices); + return (-1); + } + + if (write(fd, "} stopped cleartomark\n", 22) < 1) + { + free(choices); + return (-1); + } + } + else if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) + { + free(choices); + return (-1); + } + + free(choices); + return (0); +} + + +/* + * 'ppdEmitJCL()' - Emit code for JCL options to a file. + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */ + FILE *fp, /* I - File to write to */ + int job_id, /* I - Job ID */ + const char *user, /* I - Username */ + const char *title) /* I - Title */ +{ + const char *ptr; /* Pointer into JCL string */ + + + if (ppd == NULL || ppd->jcl_begin == NULL || ppd->jcl_ps == NULL) + return (0); + + if (strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) + { + /* + * This printer uses HP PJL commands for output; filter the output + * so that we only have a single "@PJL JOB" command in the header... + */ + + fputs("\033%-12345X", fp); + for (ptr = ppd->jcl_begin + 9; *ptr;) + if (strncmp(ptr, "@PJL JOB", 8) == 0) + { + /* + * Skip job command... + */ + + for (;*ptr; ptr ++) + if (*ptr == '\n') + break; + + if (*ptr) + ptr ++; + } + else + { + /* + * Copy line... + */ + + for (;*ptr; ptr ++) + { + putc(*ptr, fp); + if (*ptr == '\n') + break; + } + + if (*ptr) + ptr ++; + } + + /* + * Send PJL JOB command before we enter PostScript mode... + */ + + fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", title, + job_id, user, title); + } + else + fputs(ppd->jcl_begin, stdout); + + ppdEmit(ppd, stdout, PPD_ORDER_JCL); + fputs(ppd->jcl_ps, stdout); + + return (0); +} + + +/* + * 'ppd_sort()' - Sort options by ordering numbers... + */ + +static int /* O - -1 if c1 < c2, 0 if equal, 1 otherwise */ +ppd_sort(ppd_choice_t **c1, /* I - First choice */ + ppd_choice_t **c2) /* I - Second choice */ +{ + if (((ppd_option_t *)(*c1)->option)->order < ((ppd_option_t *)(*c2)->option)->order) + return (-1); + else if (((ppd_option_t *)(*c1)->option)->order > ((ppd_option_t *)(*c2)->option)->order) + return (1); + else + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/encode.c b/cups/encode.c new file mode 100644 index 0000000000..555f708e2f --- /dev/null +++ b/cups/encode.c @@ -0,0 +1,311 @@ +/* + * "$Id$" + * + * Option encoding routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsEncodeOptions() - Encode printer options into IPP attributes. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include "string.h" +#include "debug.h" + + +/* + * 'cupsEncodeOptions()' - Encode printer options into IPP attributes. + */ + +void +cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i, j; /* Looping vars */ + int count; /* Number of values */ + int n; /* Attribute value */ + char *s, /* Pointer into option value */ + *val, /* Pointer to option value */ + *copy, /* Copy of option value */ + *sep; /* Option separator */ + ipp_attribute_t *attr; /* IPP job-id attribute */ + + + DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)\n", ipp, num_options, options)); + + if (ipp == NULL || num_options < 1 || options == NULL) + return; + + /* + * Handle the document format stuff first... + */ + + if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL) + ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, val); + else if (cupsGetOption("raw", num_options, options)) + ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/vnd.cups-raw"); + else + ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/octet-stream"); + + /* + * Then add all other options... + */ + + for (i = 0; i < num_options; i ++) + { + /* + * Skip document format options - handled above... + */ + + if (strcasecmp(options[i].name, "raw") == 0 || + strcasecmp(options[i].name, "document-format") == 0 || + !options[i].name[0]) + continue; + + /* + * Count the number of values... + */ + + for (count = 1, sep = options[i].value; + (sep = strchr(sep + 1, ',')) != NULL; + count ++); + + DEBUG_printf(("cupsEncodeOptions: option = \'%s\', count = %d\n", + options[i].name, count)); + + if ((attr = _ipp_add_attr(ipp, count)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions: Ran out of memory for attributes!"); + return; + } + + attr->group_tag = IPP_TAG_JOB; + + if ((attr->name = strdup(options[i].name)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions: Ran out of memory for name!"); + return; + } + + if (count > 1) + { + /* + * Make a copy of the value we can fiddle with... + */ + + if ((copy = strdup(options[i].value)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions: Ran out of memory for value copy!"); + return; + } + + val = copy; + } + else + { + /* + * Since we have a single value, use the value directly... + */ + + val = options[i].value; + copy = NULL; + } + + /* + * See what the option value is; for compatibility with older interface + * scripts, we have to support single-argument options as well as + * option=value, option=low-high, option=MxN, and option=val1,val2,...,valN. + */ + + if (*val == '\0') + { + /* + * Old-style System V boolean value... + */ + + attr->value_tag = IPP_TAG_BOOLEAN; + + if (strncasecmp(attr->name, "no", 2) == 0) + { + DEBUG_puts("cupsEncodeOptions: Added boolean false value..."); + strcpy(attr->name, attr->name + 2); + attr->values[0].boolean = 0; + } + else + { + DEBUG_puts("cupsEncodeOptions: Added boolean true value..."); + attr->values[0].boolean = 1; + } + } + else + { + /* + * Scan the value string for values... + */ + + for (j = 0; *val != '\0'; val = sep, j ++) + { + /* + * Find the end of this value and mark it if needed... + */ + + if ((sep = strchr(val, ',')) != NULL) + *sep++ = '\0'; + else + sep = val + strlen(val); + + /* + * See what kind of value it is... + */ + + if (strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0) + { + /* + * Boolean value - true... + */ + + attr->value_tag = IPP_TAG_BOOLEAN; + attr->values[j].boolean = 1; + + DEBUG_puts("cupsEncodeOptions: Added boolean true value..."); + } + else if (strcasecmp(val, "false") == 0 || + strcasecmp(val, "off") == 0 || + strcasecmp(val, "no") == 0) + { + /* + * Boolean value - false... + */ + + attr->value_tag = IPP_TAG_BOOLEAN; + attr->values[j].boolean = 0; + + DEBUG_puts("cupsEncodeOptions: Added boolean false value..."); + } + else + { + /* + * Number, range, resolution, or string... + */ + + n = strtol(val, &s, 0); + + if (*s != '\0' && *s != '-' && (*s != 'x' || s == val)) + { + /* + * String value(s)... + */ + + if ((attr->values[j].string.text = strdup(val)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions: Ran out of memory for string!"); + return; + } + + attr->value_tag = IPP_TAG_NAME; + + DEBUG_printf(("cupsEncodeOptions: Added string value \'%s\'...\n", val)); + } + else if (*s == '-') + { + attr->value_tag = IPP_TAG_RANGE; + attr->values[j].range.lower = n; + attr->values[j].range.upper = strtol(s + 1, NULL, 0); + + DEBUG_printf(("cupsEncodeOptions: Added range option value %d-%d...\n", + n, attr->values[j].range.upper)); + } + else if (*s == 'x') + { + attr->value_tag = IPP_TAG_RESOLUTION; + attr->values[j].resolution.xres = n; + attr->values[j].resolution.yres = strtol(s + 1, &s, 0); + + if (strcasecmp(s, "dpc") == 0) + attr->values[j].resolution.units = IPP_RES_PER_CM; + else if (strcasecmp(s, "dpi") == 0) + attr->values[j].resolution.units = IPP_RES_PER_INCH; + else + { + if ((attr->values[j].string.text = strdup(val)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions: Ran out of memory for string!"); + return; + } + + attr->value_tag = IPP_TAG_NAME; + + DEBUG_printf(("cupsEncodeOptions: Added string value \'%s\'...\n", val)); + continue; + } + + DEBUG_printf(("cupsEncodeOptions: Adding resolution option value %s...\n", + val)); + } + else + { + attr->value_tag = IPP_TAG_INTEGER; + attr->values[j].integer = n; + + DEBUG_printf(("cupsEncodeOptions: Adding integer option value %d...\n", n)); + } + } + } + } + } +} + + +/* + * End of "$Id$". + */ diff --git a/cups/http.c b/cups/http.c new file mode 100644 index 0000000000..24a73130e2 --- /dev/null +++ b/cups/http.c @@ -0,0 +1,2042 @@ +/* + * "$Id$" + * + * HTTP routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * httpInitialize() - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + * httpCheck() - Check to see if there is a pending response from + * the server. + * httpClose() - Close an HTTP connection... + * httpConnect() - Connect to a HTTP server. + * httpEncryption() - Set the required encryption on the link. + * httpReconnect() - Reconnect to a HTTP server... + * httpSeparate() - Separate a Universal Resource Identifier into its + * components. + * httpSetField() - Set the value of an HTTP header. + * httpDelete() - Send a DELETE request to the server. + * httpGet() - Send a GET request to the server. + * httpHead() - Send a HEAD request to the server. + * httpOptions() - Send an OPTIONS request to the server. + * httpPost() - Send a POST request to the server. + * httpPut() - Send a PUT request to the server. + * httpTrace() - Send an TRACE request to the server. + * httpFlush() - Flush data from a HTTP connection. + * httpRead() - Read data from a HTTP connection. + * httpWrite() - Write data to a HTTP connection. + * httpGets() - Get a line of text from a HTTP connection. + * httpPrintf() - Print a formatted string to a HTTP connection. + * httpStatus() - Return a short string describing a HTTP status code. + * httpGetDateString() - Get a formatted date/time string from a time value. + * httpGetDateTime() - Get a time value from a formatted date/time string. + * httpUpdate() - Update the current HTTP state for incoming data. + * httpDecode64() - Base64-decode a string. + * httpEncode64() - Base64-encode a string. + * httpGetLength() - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * http_field() - Return the field index for a field name. + * http_send() - Send a request with all fields and the trailing + * blank line. + * http_upgrade() - Force upgrade to TLS encryption. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include "string.h" +#include +#include + +#include "http.h" +#include "ipp.h" +#include "debug.h" + +#if !defined(WIN32) && !defined(__EMX__) +# include +#endif /* !WIN32 && !__EMX__ */ + +#ifdef HAVE_LIBSSL +# include +# include +# include +#endif /* HAVE_LIBSSL */ + + +/* + * Some operating systems have done away with the Fxxxx constants for + * the fcntl() call; this works around that "feature"... + */ + +#ifndef FNONBLK +# define FNONBLK O_NONBLOCK +#endif /* !FNONBLK */ + + +/* + * Local functions... + */ + +static http_field_t http_field(const char *name); +static int http_send(http_t *http, http_state_t request, + const char *uri); +#ifdef HAVE_LIBSSL +static int http_upgrade(http_t *http); +#endif /* HAVE_LIBSSL */ + + +/* + * Local globals... + */ + +static const char *http_fields[] = + { + "Accept-Language", + "Accept-Ranges", + "Authorization", + "Connection", + "Content-Encoding", + "Content-Language", + "Content-Length", + "Content-Location", + "Content-MD5", + "Content-Range", + "Content-Type", + "Content-Version", + "Date", + "Host", + "If-Modified-Since", + "If-Unmodified-since", + "Keep-Alive", + "Last-Modified", + "Link", + "Location", + "Range", + "Referer", + "Retry-After", + "Transfer-Encoding", + "Upgrade", + "User-Agent", + "WWW-Authenticate" + }; +static const char *days[7] = + { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + }; +static const char *months[12] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + +/* + * 'httpInitialize()' - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + */ + +void +httpInitialize(void) +{ +#ifdef HAVE_LIBSSL + struct timeval curtime; /* Current time in microseconds */ + int i; /* Looping var */ + unsigned char data[1024]; /* Seed data */ +#endif /* HAVE_LIBSSL */ + +#if defined(WIN32) || defined(__EMX__) + WSADATA winsockdata; /* WinSock data */ + static int initialized = 0;/* Has WinSock been initialized? */ + + + if (!initialized) + WSAStartup(MAKEWORD(1,1), &winsockdata); +#elif defined(HAVE_SIGSET) + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + struct sigaction action; /* POSIX sigaction data */ + + + /* + * Ignore SIGPIPE signals... + */ + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* WIN32 || __EMX__ */ + +#ifdef HAVE_LIBSSL + SSL_load_error_strings(); + SSL_library_init(); + + /* + * Using the current time is a dubious random seed, but on some systems + * it is the best we can do (on others, this seed isn't even used...) + */ + + gettimeofday(&curtime, NULL); + srand(curtime.tv_sec + curtime.tv_usec); + + for (i = 0; i < sizeof(data); i ++) + data[i] = rand(); /* Yes, this is a poor source of random data... */ + + RAND_seed(&data, sizeof(data)); +#endif /* HAVE_LIBSSL */ +} + + +/* + * 'httpCheck()' - Check to see if there is a pending response from the server. + */ + +int /* O - 0 = no data, 1 = data available */ +httpCheck(http_t *http) /* I - HTTP connection */ +{ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout */ + + + /* + * First see if there is data in the buffer... + */ + + if (http == NULL) + return (0); + + if (http->used) + return (1); + + /* + * Then try doing a select() to poll the socket... + */ + + FD_ZERO(&input); + FD_SET(http->fd, &input); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + return (select(http->fd + 1, &input, NULL, NULL, &timeout) > 0); +} + + +/* + * 'httpClose()' - Close an HTTP connection... + */ + +void +httpClose(http_t *http) /* I - Connection to close */ +{ +#ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ +#endif /* HAVE_LIBSSL */ + + + if (!http) + return; + +#ifdef HAVE_LIBSSL + if (http->tls) + { + conn = (SSL *)(http->tls); + context = SSL_get_SSL_CTX(conn); + + SSL_shutdown(conn); + SSL_CTX_free(context); + SSL_free(conn); + + http->tls = NULL; + } +#endif /* HAVE_LIBSSL */ + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + free(http); +} + + +/* + * 'httpConnect()' - Connect to a HTTP server. + */ + +http_t * /* O - New HTTP connection */ +httpConnect(const char *host, /* I - Host to connect to */ + int port) /* I - Port number */ +{ + http_t *http; /* New HTTP connection */ + struct hostent *hostaddr; /* Host address data */ + + + if (host == NULL) + return (NULL); + + httpInitialize(); + + /* + * Lookup the host... + */ + + if ((hostaddr = gethostbyname(host)) == NULL) + { + /* + * This hack to make users that don't have a localhost entry in + * their hosts file or DNS happy... + */ + + if (strcasecmp(host, "localhost") != 0) + return (NULL); + else if ((hostaddr = gethostbyname("127.0.0.1")) == NULL) + return (NULL); + } + + /* + * Verify that it is an IPv4 address (IPv6 support will come in CUPS 1.2...) + */ + + if (hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) + return (NULL); + + /* + * Allocate memory for the structure... + */ + + http = calloc(sizeof(http_t), 1); + if (http == NULL) + return (NULL); + + http->version = HTTP_1_1; + http->blocking = 1; + http->activity = time(NULL); + http->fd = -1; + + /* + * Copy the hostname and port and then "reconnect"... + */ + + strncpy(http->hostname, host, sizeof(http->hostname) - 1); + memcpy((char *)&(http->hostaddr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + http->hostaddr.sin_family = hostaddr->h_addrtype; +#ifdef WIN32 + http->hostaddr.sin_port = htons((u_short)port); +#else + http->hostaddr.sin_port = htons(port); +#endif /* WIN32 */ + + /* + * Set the default encryption status... + */ + + if (port == 443) + http->encryption = HTTP_ENCRYPT_ALWAYS; + + /* + * Connect to the remote system... + */ + + if (httpReconnect(http)) + { + free(http); + return (NULL); + } + else + return (http); +} + + +/* + * 'httpEncryption()' - Set the required encryption on the link. + */ + +int /* O - -1 on error, 0 on success */ +httpEncryption(http_t *http, /* I - HTTP data */ + http_encryption_t e) /* I - New encryption preference */ +{ +#ifdef HAVE_LIBSSL + if (!http) + return (0); + + http->encryption = e; + + if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) || + (http->encryption == HTTP_ENCRYPT_NEVER && http->tls)) + return (httpReconnect(http)); + else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) + return (http_upgrade(http)); + else + return (0); +#else + if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED) + return (-1); + else + return (0); +#endif /* HAVE_LIBSSL */ +} + + +/* + * 'httpReconnect()' - Reconnect to a HTTP server... + */ + +int /* O - 0 on success, non-zero on failure */ +httpReconnect(http_t *http) /* I - HTTP data */ +{ + int val; /* Socket option value */ +#ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ + + + if (http->tls) + { + conn = (SSL *)(http->tls); + context = SSL_get_SSL_CTX(conn); + + SSL_shutdown(conn); + SSL_CTX_free(context); + SSL_free(conn); + + http->tls = NULL; + } +#endif /* HAVE_LIBSSL */ + + /* + * Close any previously open socket... + */ + + if (http->fd >= 0) +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + /* + * Create the socket and set options to allow reuse. + */ + + if ((http->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + return (-1); + } + +#ifdef FD_CLOEXEC + fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting * + * other processes... */ +#endif /* FD_CLOEXEC */ + + val = 1; + setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); + +#ifdef SO_REUSEPORT + val = 1; + setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); +#endif /* SO_REUSEPORT */ + + /* + * Connect to the server... + */ + + if (connect(http->fd, (struct sockaddr *)&(http->hostaddr), + sizeof(http->hostaddr)) < 0) + { +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + http->fd = -1; + + return (-1); + } + + http->error = 0; + http->status = HTTP_CONTINUE; + +#ifdef HAVE_LIBSSL + if (http->encryption == HTTP_ENCRYPT_ALWAYS) + { + /* + * Always do encryption via SSL. + */ + + context = SSL_CTX_new(SSLv23_method()); + conn = SSL_new(context); + + SSL_set_fd(conn, http->fd); + if (SSL_connect(conn) != 1) + { + SSL_CTX_free(context); + SSL_free(conn); + +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + return (-1); + } + + http->tls = conn; + } + else if (http->encryption == HTTP_ENCRYPT_REQUIRED) + return (http_upgrade(http)); +#endif /* HAVE_LIBSSL */ + + return (0); +} + + +/* + * 'httpSeparate()' - Separate a Universal Resource Identifier into its + * components. + */ + +void +httpSeparate(const char *uri, /* I - Universal Resource Identifier */ + char *method, /* O - Method [32] (http, https, etc.) */ + char *username, /* O - Username [32] */ + char *host, /* O - Hostname [32] */ + int *port, /* O - Port number to use */ + char *resource) /* O - Resource/filename [1024] */ +{ + char *ptr; /* Pointer into string... */ + const char *atsign, /* @ sign */ + *slash; /* Separator */ + char safeuri[HTTP_MAX_URI]; /* "Safe" local copy of URI */ + + + /* + * Range check input... + */ + + if (uri == NULL || method == NULL || username == NULL || host == NULL || + port == NULL || resource == NULL) + return; + + /* + * Copy the URL to a local string to make sure we don't have a URL + * longer than HTTP_MAX_URI characters long... + */ + + strncpy(safeuri, uri, sizeof(safeuri)); + safeuri[sizeof(safeuri) - 1] = '\0'; + + uri = safeuri; + + /* + * Grab the method portion of the URI... + */ + + if (strncmp(uri, "//", 2) == 0) + { + /* + * Workaround for HP IPP client bug... + */ + + strcpy(method, "ipp"); + } + else + { + /* + * Standard URI with method... + */ + + for (ptr = host; *uri != ':' && *uri != '\0'; uri ++) + if (ptr < (host + HTTP_MAX_URI - 1)) + *ptr++ = *uri; + + *ptr = '\0'; + if (*uri == ':') + uri ++; + + /* + * If the method contains a period or slash, then it's probably + * hostname/filename... + */ + + if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0') + { + if ((ptr = strchr(host, '/')) != NULL) + { + strncpy(resource, ptr, HTTP_MAX_URI); + resource[HTTP_MAX_URI - 1] = '\0'; + *ptr = '\0'; + } + else + resource[0] = '\0'; + + if (isdigit(*uri)) + { + /* + * OK, we have "hostname:port[/resource]"... + */ + + *port = strtol(uri, (char **)&uri, 10); + + if (*uri == '/') + { + strncpy(resource, uri, HTTP_MAX_URI); + resource[HTTP_MAX_URI - 1] = '\0'; + } + } + else + *port = 631; + + strcpy(method, "http"); + username[0] = '\0'; + return; + } + else + { + strncpy(method, host, 31); + method[31] = '\0'; + } + } + + /* + * If the method starts with less than 2 slashes then it is a local resource... + */ + + if (strncmp(uri, "//", 2) != 0) + { + strncpy(resource, uri, 1023); + resource[1023] = '\0'; + + username[0] = '\0'; + host[0] = '\0'; + *port = 0; + return; + } + + /* + * Grab the username, if any... + */ + + while (*uri == '/') + uri ++; + + if ((slash = strchr(uri, '/')) == NULL) + slash = uri + strlen(uri); + + if ((atsign = strchr(uri, '@')) != NULL && atsign < slash) + { + /* + * Got a username:password combo... + */ + + for (ptr = username; uri < atsign; uri ++) + if (ptr < (username + HTTP_MAX_URI - 1)) + *ptr++ = *uri; + + *ptr = '\0'; + + uri = atsign + 1; + } + else + username[0] = '\0'; + + /* + * Grab the hostname... + */ + + for (ptr = host; *uri != ':' && *uri != '/' && *uri != '\0'; uri ++) + if (ptr < (host + HTTP_MAX_URI - 1)) + *ptr++ = *uri; + + *ptr = '\0'; + + if (*uri != ':') + { + if (strcasecmp(method, "http") == 0) + *port = 80; + else if (strcasecmp(method, "https") == 0) + *port = 443; + else if (strcasecmp(method, "ipp") == 0) + *port = ippPort(); + else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */ + *port = 9100; + else + *port = 0; + } + else + { + /* + * Parse port number... + */ + + *port = 0; + uri ++; + while (isdigit(*uri)) + { + *port = (*port * 10) + *uri - '0'; + uri ++; + } + } + + if (*uri == '\0') + { + /* + * Hostname but no port or path... + */ + + resource[0] = '/'; + resource[1] = '\0'; + return; + } + + /* + * The remaining portion is the resource string... + */ + + strncpy(resource, uri, HTTP_MAX_URI); + resource[HTTP_MAX_URI - 1] = '\0'; +} + + +/* + * 'httpGetSubField()' - Get a sub-field value. + */ + +char * /* O - Value or NULL */ +httpGetSubField(http_t *http, /* I - HTTP data */ + http_field_t field, /* I - Field index */ + const char *name, /* I - Name of sub-field */ + char *value) /* O - Value string */ +{ + const char *fptr; /* Pointer into field */ + char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ + *ptr; /* Pointer into string buffer */ + + + if (http == NULL || + field < HTTP_FIELD_ACCEPT_LANGUAGE || + field > HTTP_FIELD_WWW_AUTHENTICATE || + name == NULL || value == NULL) + return (NULL); + + for (fptr = http->fields[field]; *fptr;) + { + /* + * Skip leading whitespace... + */ + + while (isspace(*fptr)) + fptr ++; + + if (*fptr == ',') + { + fptr ++; + continue; + } + + /* + * Get the sub-field name... + */ + + for (ptr = temp; + *fptr && *fptr != '=' && !isspace(*fptr) && ptr < (temp + sizeof(temp) - 1); + *ptr++ = *fptr++); + + *ptr = '\0'; + + /* + * Skip trailing chars up to the '='... + */ + + while (*fptr && *fptr != '=') + fptr ++; + + if (!*fptr) + break; + + /* + * Skip = and leading whitespace... + */ + + fptr ++; + + while (isspace(*fptr)) + fptr ++; + + if (*fptr == '\"') + { + /* + * Read quoted string... + */ + + for (ptr = value, fptr ++; + *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1); + *ptr++ = *fptr++); + + *ptr = '\0'; + + while (*fptr && *fptr != '\"') + fptr ++; + + if (*fptr) + fptr ++; + } + else + { + /* + * Read unquoted string... + */ + + for (ptr = value; + *fptr && !isspace(*fptr) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1); + *ptr++ = *fptr++); + + *ptr = '\0'; + + while (*fptr && !isspace(*fptr) && *fptr != ',') + fptr ++; + } + + /* + * See if this is the one... + */ + + if (strcmp(name, temp) == 0) + return (value); + } + + value[0] = '\0'; + + return (NULL); +} + + +/* + * 'httpSetField()' - Set the value of an HTTP header. + */ + +void +httpSetField(http_t *http, /* I - HTTP data */ + http_field_t field, /* I - Field index */ + const char *value) /* I - Value */ +{ + if (http == NULL || + field < HTTP_FIELD_ACCEPT_LANGUAGE || + field > HTTP_FIELD_WWW_AUTHENTICATE || + value == NULL) + return; + + strncpy(http->fields[field], value, HTTP_MAX_VALUE - 1); + http->fields[field][HTTP_MAX_VALUE - 1] = '\0'; +} + + +/* + * 'httpDelete()' - Send a DELETE request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpDelete(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to delete */ +{ + return (http_send(http, HTTP_DELETE, uri)); +} + + +/* + * 'httpGet()' - Send a GET request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpGet(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to get */ +{ + return (http_send(http, HTTP_GET, uri)); +} + + +/* + * 'httpHead()' - Send a HEAD request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpHead(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for head */ +{ + return (http_send(http, HTTP_HEAD, uri)); +} + + +/* + * 'httpOptions()' - Send an OPTIONS request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpOptions(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for options */ +{ + return (http_send(http, HTTP_OPTIONS, uri)); +} + + +/* + * 'httpPost()' - Send a POST request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpPost(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for post */ +{ + httpGetLength(http); + + return (http_send(http, HTTP_POST, uri)); +} + + +/* + * 'httpPut()' - Send a PUT request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpPut(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to put */ +{ + httpGetLength(http); + + return (http_send(http, HTTP_PUT, uri)); +} + + +/* + * 'httpTrace()' - Send an TRACE request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpTrace(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for trace */ +{ + return (http_send(http, HTTP_TRACE, uri)); +} + + +/* + * 'httpFlush()' - Flush data from a HTTP connection. + */ + +void +httpFlush(http_t *http) /* I - HTTP data */ +{ + char buffer[8192]; /* Junk buffer */ + + + while (httpRead(http, buffer, sizeof(buffer)) > 0); +} + + +/* + * 'httpRead()' - Read data from a HTTP connection. + */ + +int /* O - Number of bytes read */ +httpRead(http_t *http, /* I - HTTP data */ + char *buffer, /* I - Buffer for data */ + int length) /* I - Maximum number of bytes */ +{ + int bytes; /* Bytes read */ + char len[32]; /* Length string */ + + + DEBUG_printf(("httpRead(%08x, %08x, %d)\n", http, buffer, length)); + + if (http == NULL || buffer == NULL) + return (-1); + + http->activity = time(NULL); + + if (length <= 0) + return (0); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + http->data_remaining <= 0) + { + DEBUG_puts("httpRead: Getting chunk length..."); + + if (httpGets(len, sizeof(len), http) == NULL) + { + DEBUG_puts("httpRead: Could not get length!"); + return (0); + } + + http->data_remaining = strtol(len, NULL, 16); + } + + DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining)); + + if (http->data_remaining == 0) + { + /* + * A zero-length chunk ends a transfer; unless we are reading POST + * data, go idle... + */ + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + httpGets(len, sizeof(len), http); + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + + return (0); + } + else if (length > http->data_remaining) + length = http->data_remaining; + + if (http->used > 0) + { + if (length > http->used) + length = http->used; + + bytes = length; + + DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes)); + + memcpy(buffer, http->buffer, length); + http->used -= length; + + if (http->used > 0) + memcpy(http->buffer, http->buffer + length, http->used); + } +#ifdef HAVE_LIBSSL + else if (http->tls) + bytes = SSL_read((SSL *)(http->tls), buffer, length); +#endif /* HAVE_LIBSSL */ + else + { + DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length)); + bytes = recv(http->fd, buffer, length, 0); + DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes)); + } + + if (bytes > 0) + http->data_remaining -= bytes; + else if (bytes < 0) +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + + if (http->data_remaining == 0) + { + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + httpGets(len, sizeof(len), http); + + if (http->data_encoding != HTTP_ENCODE_CHUNKED) + { + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + } + } + + return (bytes); +} + + +/* + * 'httpWrite()' - Write data to a HTTP connection. + */ + +int /* O - Number of bytes written */ +httpWrite(http_t *http, /* I - HTTP data */ + const char *buffer, /* I - Buffer for data */ + int length) /* I - Number of bytes to write */ +{ + int tbytes, /* Total bytes sent */ + bytes; /* Bytes sent */ + + + if (http == NULL || buffer == NULL) + return (-1); + + http->activity = time(NULL); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + { + if (httpPrintf(http, "%x\r\n", length) < 0) + return (-1); + + if (length == 0) + { + /* + * A zero-length chunk ends a transfer; unless we are sending POST + * data, go idle... + */ + + DEBUG_puts("httpWrite: changing states..."); + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + + if (httpPrintf(http, "\r\n") < 0) + return (-1); + + return (0); + } + } + + tbytes = 0; + + while (length > 0) + { +#ifdef HAVE_LIBSSL + if (http->tls) + bytes = SSL_write((SSL *)(http->tls), buffer, length); + else +#endif /* HAVE_LIBSSL */ + bytes = send(http->fd, buffer, length, 0); + + if (bytes < 0) + { + DEBUG_puts("httpWrite: error writing data...\n"); + + return (-1); + } + + buffer += bytes; + tbytes += bytes; + length -= bytes; + if (http->data_encoding == HTTP_ENCODE_LENGTH) + http->data_remaining -= bytes; + } + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + if (httpPrintf(http, "\r\n") < 0) + return (-1); + + if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH) + { + /* + * Finished with the transfer; unless we are sending POST data, go idle... + */ + + DEBUG_puts("httpWrite: changing states..."); + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + } + + DEBUG_printf(("httpWrite: wrote %d bytes...\n", tbytes)); + + return (tbytes); +} + + +/* + * 'httpGets()' - Get a line of text from a HTTP connection. + */ + +char * /* O - Line or NULL */ +httpGets(char *line, /* I - Line to read into */ + int length, /* I - Max length of buffer */ + http_t *http) /* I - HTTP data */ +{ + char *lineptr, /* Pointer into line */ + *bufptr, /* Pointer into input buffer */ + *bufend; /* Pointer to end of buffer */ + int bytes; /* Number of bytes read */ + + + DEBUG_printf(("httpGets(%08x, %d, %08x)\n", line, length, http)); + + if (http == NULL || line == NULL) + return (NULL); + + /* + * Pre-scan the buffer and see if there is a newline in there... + */ + +#if defined(WIN32) || defined(__EMX__) + WSASetLastError(0); +#else + errno = 0; +#endif /* WIN32 || __EMX__ */ + + do + { + bufptr = http->buffer; + bufend = http->buffer + http->used; + + while (bufptr < bufend) + if (*bufptr == 0x0a) + break; + else + bufptr ++; + + if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER) + { + /* + * No newline; see if there is more data to be read... + */ + +#ifdef HAVE_LIBSSL + if (http->tls) + bytes = SSL_read((SSL *)(http->tls), bufend, + HTTP_MAX_BUFFER - http->used); + else +#endif /* HAVE_LIBSSL */ + bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0); + + if (bytes < 0) + { + /* + * Nope, can't get a line this time... + */ + +#if defined(WIN32) || defined(__EMX__) + if (WSAGetLastError() != http->error) + { + http->error = WSAGetLastError(); + continue; + } + + DEBUG_printf(("httpGets(): recv() error %d!\n", WSAGetLastError())); +#else + if (errno != http->error) + { + http->error = errno; + continue; + } + + DEBUG_printf(("httpGets(): recv() error %d!\n", errno)); +#endif /* WIN32 || __EMX__ */ + + return (NULL); + } + else if (bytes == 0) + { + if (http->blocking) + http->error = EPIPE; + + return (NULL); + } + + /* + * Yup, update the amount used and the end pointer... + */ + + http->used += bytes; + bufend += bytes; + } + } + while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER); + + http->activity = time(NULL); + + /* + * Read a line from the buffer... + */ + + lineptr = line; + bufptr = http->buffer; + bytes = 0; + length --; + + while (bufptr < bufend && bytes < length) + { + bytes ++; + + if (*bufptr == 0x0a) + { + bufptr ++; + break; + } + else if (*bufptr == 0x0d) + bufptr ++; + else + *lineptr++ = *bufptr++; + } + + if (bytes > 0) + { + *lineptr = '\0'; + + http->used -= bytes; + if (http->used > 0) + memcpy(http->buffer, bufptr, http->used); + + DEBUG_printf(("httpGets(): Returning \"%s\"\n", line)); + return (line); + } + + DEBUG_puts("httpGets(): No new line available!"); + + return (NULL); +} + + +/* + * 'httpPrintf()' - Print a formatted string to a HTTP connection. + */ + +int /* O - Number of bytes written */ +httpPrintf(http_t *http, /* I - HTTP data */ + const char *format, /* I - printf-style format string */ + ...) /* I - Additional args as needed */ +{ + int bytes, /* Number of bytes to write */ + nbytes, /* Number of bytes written */ + tbytes; /* Number of bytes all together */ + char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */ + *bufptr; /* Pointer into buffer */ + va_list ap; /* Variable argument pointer */ + + + va_start(ap, format); + bytes = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + DEBUG_printf(("httpPrintf: %s", buf)); + + for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes) + { +#ifdef HAVE_LIBSSL + if (http->tls) + nbytes = SSL_write((SSL *)(http->tls), bufptr, bytes - tbytes); + else +#endif /* HAVE_LIBSSL */ + nbytes = send(http->fd, bufptr, bytes - tbytes, 0); + + if (nbytes < 0) + return (-1); + } + + return (bytes); +} + + +/* + * 'httpStatus()' - Return a short string describing a HTTP status code. + */ + +const char * /* O - String or NULL */ +httpStatus(http_status_t status) /* I - HTTP status code */ +{ + switch (status) + { + case HTTP_CONTINUE : + return ("Continue"); + case HTTP_SWITCHING_PROTOCOLS : + return ("Switching Protocols"); + case HTTP_OK : + return ("OK"); + case HTTP_CREATED : + return ("Created"); + case HTTP_ACCEPTED : + return ("Accepted"); + case HTTP_NO_CONTENT : + return ("No Content"); + case HTTP_NOT_MODIFIED : + return ("Not Modified"); + case HTTP_BAD_REQUEST : + return ("Bad Request"); + case HTTP_UNAUTHORIZED : + return ("Unauthorized"); + case HTTP_FORBIDDEN : + return ("Forbidden"); + case HTTP_NOT_FOUND : + return ("Not Found"); + case HTTP_REQUEST_TOO_LARGE : + return ("Request Entity Too Large"); + case HTTP_URI_TOO_LONG : + return ("URI Too Long"); + case HTTP_UPGRADE_REQUIRED : + return ("Upgrade Required"); + case HTTP_NOT_IMPLEMENTED : + return ("Not Implemented"); + case HTTP_NOT_SUPPORTED : + return ("Not Supported"); + default : + return ("Unknown"); + } +} + + +/* + * 'httpGetDateString()' - Get a formatted date/time string from a time value. + */ + +const char * /* O - Date/time string */ +httpGetDateString(time_t t) /* I - UNIX time */ +{ + struct tm *tdate; + static char datetime[256]; + + + tdate = gmtime(&t); + snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT", + days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon], + tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec); + + return (datetime); +} + + +/* + * 'httpGetDateTime()' - Get a time value from a formatted date/time string. + */ + +time_t /* O - UNIX time */ +httpGetDateTime(const char *s) /* I - Date/time string */ +{ + int i; /* Looping var */ + struct tm tdate; /* Time/date structure */ + char mon[16]; /* Abbreviated month name */ + int day, year; /* Day of month and year */ + int hour, min, sec; /* Time */ + + + if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) + return (0); + + for (i = 0; i < 12; i ++) + if (strcasecmp(mon, months[i]) == 0) + break; + + if (i >= 12) + return (0); + + tdate.tm_mon = i; + tdate.tm_mday = day; + tdate.tm_year = year - 1900; + tdate.tm_hour = hour; + tdate.tm_min = min; + tdate.tm_sec = sec; + tdate.tm_isdst = 0; + + return (mktime(&tdate)); +} + + +/* + * 'httpUpdate()' - Update the current HTTP state for incoming data. + */ + +http_status_t /* O - HTTP status */ +httpUpdate(http_t *http) /* I - HTTP data */ +{ + char line[1024], /* Line from connection... */ + *value; /* Pointer to value on line */ + http_field_t field; /* Field index */ + int major, minor; /* HTTP version numbers */ + http_status_t status; /* Authorization status */ +#ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ +#endif /* HAVE_LIBSSL */ + + + DEBUG_printf(("httpUpdate(%08x)\n", http)); + + /* + * If we haven't issued any commands, then there is nothing to "update"... + */ + + if (http->state == HTTP_WAITING) + return (HTTP_CONTINUE); + + /* + * Grab all of the lines we can from the connection... + */ + + while (httpGets(line, sizeof(line), http) != NULL) + { + DEBUG_puts(line); + + if (line[0] == '\0') + { + /* + * Blank line means the start of the data section (if any). Return + * the result code, too... + * + * If we get status 100 (HTTP_CONTINUE), then we *don't* change states. + * Instead, we just return HTTP_CONTINUE to the caller and keep on + * tryin'... + */ + + if (http->status == HTTP_CONTINUE) + return (http->status); + +#ifdef HAVE_LIBSSL + if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) + { + context = SSL_CTX_new(SSLv23_method()); + conn = SSL_new(context); + + SSL_set_fd(conn, http->fd); + if (SSL_connect(conn) != 1) + { + SSL_CTX_free(context); + SSL_free(conn); + +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + return (HTTP_ERROR); + } + + http->tls = conn; + + return (HTTP_CONTINUE); + } + else if (http->status == HTTP_UPGRADE_REQUIRED && + http->encryption != HTTP_ENCRYPT_NEVER) + http->encryption = HTTP_ENCRYPT_REQUIRED; +#endif /* HAVE_LIBSSL */ + + httpGetLength(http); + + switch (http->state) + { + case HTTP_GET : + case HTTP_POST : + case HTTP_POST_RECV : + case HTTP_PUT : + http->state ++; + break; + + default : + http->state = HTTP_WAITING; + break; + } + + return (http->status); + } + else if (strncmp(line, "HTTP/", 5) == 0) + { + /* + * Got the beginning of a response... + */ + + if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, (int *)&status) != 3) + return (HTTP_ERROR); + + http->version = (http_version_t)(major * 100 + minor); + http->status = status; + } + else if ((value = strchr(line, ':')) != NULL) + { + /* + * Got a value... + */ + + *value++ = '\0'; + while (isspace(*value)) + value ++; + + /* + * Be tolerants of servers that send unknown attribute fields... + */ + + if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN) + { + DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line)); + continue; + } + + httpSetField(http, field, value); + } + else + { + http->status = HTTP_ERROR; + return (HTTP_ERROR); + } + } + + /* + * See if there was an error... + */ + + if (http->error) + { + http->status = HTTP_ERROR; + return (HTTP_ERROR); + } + + /* + * If we haven't already returned, then there is nothing new... + */ + + return (HTTP_CONTINUE); +} + + +/* + * 'httpDecode64()' - Base64-decode a string. + */ + +char * /* O - Decoded string */ +httpDecode64(char *out, /* I - String to write to */ + const char *in) /* I - String to read from */ +{ + int pos, /* Bit position */ + base64; /* Value of this character */ + char *outptr; /* Output pointer */ + + + for (outptr = out, pos = 0; *in != '\0'; in ++) + { + /* + * Decode this character into a number from 0 to 63... + */ + + if (*in >= 'A' && *in <= 'Z') + base64 = *in - 'A'; + else if (*in >= 'a' && *in <= 'z') + base64 = *in - 'a' + 26; + else if (*in >= '0' && *in <= '9') + base64 = *in - '0' + 52; + else if (*in == '+') + base64 = 62; + else if (*in == '/') + base64 = 63; + else if (*in == '=') + break; + else + continue; + + /* + * Store the result in the appropriate chars... + */ + + switch (pos) + { + case 0 : + *outptr = base64 << 2; + pos ++; + break; + case 1 : + *outptr++ |= (base64 >> 4) & 3; + *outptr = (base64 << 4) & 255; + pos ++; + break; + case 2 : + *outptr++ |= (base64 >> 2) & 15; + *outptr = (base64 << 6) & 255; + pos ++; + break; + case 3 : + *outptr++ |= base64; + pos = 0; + break; + } + } + + *outptr = '\0'; + + /* + * Return the decoded string... + */ + + return (out); +} + + +/* + * 'httpEncode64()' - Base64-encode a string. + */ + +char * /* O - Encoded string */ +httpEncode64(char *out, /* I - String to write to */ + const char *in) /* I - String to read from */ +{ + char *outptr; /* Output pointer */ + static char base64[] = /* Base64 characters... */ + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/" + }; + + + for (outptr = out; *in != '\0'; in ++) + { + /* + * Encode the up to 3 characters as 4 Base64 numbers... + */ + + *outptr ++ = base64[in[0] >> 2]; + *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63]; + + in ++; + if (*in == '\0') + { + *outptr ++ = '='; + break; + } + + *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63]; + + in ++; + if (*in == '\0') + break; + + *outptr ++ = base64[in[0] & 63]; + } + + *outptr ++ = '='; + *outptr = '\0'; + + /* + * Return the encoded string... + */ + + return (out); +} + + +/* + * 'httpGetLength()' - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + */ + +int /* O - Content length */ +httpGetLength(http_t *http) /* I - HTTP data */ +{ + DEBUG_printf(("httpGetLength(%08x)\n", http)); + + if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0) + { + DEBUG_puts("httpGetLength: chunked request!"); + + http->data_encoding = HTTP_ENCODE_CHUNKED; + http->data_remaining = 0; + } + else + { + http->data_encoding = HTTP_ENCODE_LENGTH; + + /* + * The following is a hack for HTTP servers that don't send a + * content-length or transfer-encoding field... + * + * If there is no content-length then the connection must close + * after the transfer is complete... + */ + + if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0') + http->data_remaining = 2147483647; + else + http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]); + + DEBUG_printf(("httpGetLength: content_length = %d\n", http->data_remaining)); + } + + return (http->data_remaining); +} + + +/* + * 'http_field()' - Return the field index for a field name. + */ + +static http_field_t /* O - Field index */ +http_field(const char *name) /* I - String name */ +{ + int i; /* Looping var */ + + + for (i = 0; i < HTTP_FIELD_MAX; i ++) + if (strcasecmp(name, http_fields[i]) == 0) + return ((http_field_t)i); + + return (HTTP_FIELD_UNKNOWN); +} + + +/* + * 'http_send()' - Send a request with all fields and the trailing blank line. + */ + +static int /* O - 0 on success, non-zero on error */ +http_send(http_t *http, /* I - HTTP data */ + http_state_t request, /* I - Request code */ + const char *uri) /* I - URI */ +{ + int i; /* Looping var */ + char *ptr, /* Pointer in buffer */ + buf[1024]; /* Encoded URI buffer */ + static const char *codes[] = /* Request code strings */ + { + NULL, + "OPTIONS", + "GET", + NULL, + "HEAD", + "POST", + NULL, + NULL, + "PUT", + NULL, + "DELETE", + "TRACE", + "CLOSE" + }; + static const char *hex = "0123456789ABCDEF"; + /* Hex digits */ + + + if (http == NULL || uri == NULL) + return (-1); + + /* + * Encode the URI as needed... + */ + + for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++) + if (*uri <= ' ' || *uri >= 127) + { + if (ptr < (buf + sizeof(buf) - 1)) + *ptr ++ = '%'; + if (ptr < (buf + sizeof(buf) - 1)) + *ptr ++ = hex[(*uri >> 4) & 15]; + if (ptr < (buf + sizeof(buf) - 1)) + *ptr ++ = hex[*uri & 15]; + } + else + *ptr ++ = *uri; + + *ptr = '\0'; + + /* + * See if we had an error the last time around; if so, reconnect... + */ + + if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST) + httpReconnect(http); + + /* + * Send the request header... + */ + + http->state = request; + if (request == HTTP_POST || request == HTTP_PUT) + http->state ++; + + http->status = HTTP_CONTINUE; + +#ifdef HAVE_LIBSSL + if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) + { + httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); + httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0"); + } +#endif /* HAVE_LIBSSL */ + + if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) + { + http->status = HTTP_ERROR; + return (-1); + } + + for (i = 0; i < HTTP_FIELD_MAX; i ++) + if (http->fields[i][0] != '\0') + { + DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i])); + + if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1) + { + http->status = HTTP_ERROR; + return (-1); + } + } + + if (httpPrintf(http, "\r\n") < 1) + { + http->status = HTTP_ERROR; + return (-1); + } + + httpClearFields(http); + + return (0); +} + + +#ifdef HAVE_LIBSSL +/* + * 'http_upgrade()' - Force upgrade to TLS encryption. + */ + +static int /* O - Status of connection */ +http_upgrade(http_t *http) /* I - HTTP data */ +{ + int ret; /* Return value */ + http_t myhttp; /* Local copy of HTTP data */ + + + DEBUG_printf(("http_upgrade(%p)\n", http)); + + /* + * Copy the HTTP data to a local variable so we can do the OPTIONS + * request without interfering with the existing request data... + */ + + memcpy(&myhttp, http, sizeof(myhttp)); + + /* + * Send an OPTIONS request to the server, requiring SSL or TLS + * encryption on the link... + */ + + httpClearFields(&myhttp); + httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade"); + httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0"); + + if ((ret = httpOptions(&myhttp, "*")) == 0) + { + /* + * Wait for the secure connection... + */ + + while (httpUpdate(&myhttp) == HTTP_CONTINUE); + } + + httpFlush(&myhttp); + + /* + * Copy the HTTP data back over, if any... + */ + + http->fd = myhttp.fd; + http->error = myhttp.error; + http->activity = myhttp.activity; + http->status = myhttp.status; + http->version = myhttp.version; + http->keep_alive = myhttp.keep_alive; + http->used = myhttp.used; + + if (http->used) + memcpy(http->buffer, myhttp.buffer, http->used); + + http->auth_type = myhttp.auth_type; + http->nonce_count = myhttp.nonce_count; + + memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce)); + + http->tls = myhttp.tls; + http->encryption = myhttp.encryption; + + /* + * See if we actually went secure... + */ + + if (!http->tls) + { + /* + * Server does not support HTTP upgrade... + */ + + DEBUG_puts("Server does not support HTTP upgrade!"); + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + http->fd = -1; + + return (-1); + } + else + return (ret); +} +#endif /* HAVE_LIBSSL */ + + +/* + * End of "$Id$". + */ diff --git a/cups/http.h b/cups/http.h new file mode 100644 index 0000000000..1c107b9507 --- /dev/null +++ b/cups/http.h @@ -0,0 +1,342 @@ +/* + * "$Id$" + * + * Hyper-Text Transport Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_HTTP_H_ +# define _CUPS_HTTP_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# if defined(WIN32) || defined(__EMX__) +# include +# else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif /* WIN32 || __EMX__ */ + +# include "md5.h" + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Limits... + */ + +# define HTTP_MAX_URI 1024 /* Max length of URI string */ +# define HTTP_MAX_HOST 256 /* Max length of hostname string */ +# define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */ +# define HTTP_MAX_VALUE 256 /* Max header field value length */ + + +/* + * HTTP state values... + */ + +typedef enum /* States are server-oriented */ +{ + HTTP_WAITING, /* Waiting for command */ + HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */ + HTTP_GET, /* GET command, waiting for blank line */ + HTTP_GET_SEND, /* GET command, sending data */ + HTTP_HEAD, /* HEAD command, waiting for blank line */ + HTTP_POST, /* POST command, waiting for blank line */ + HTTP_POST_RECV, /* POST command, receiving data */ + HTTP_POST_SEND, /* POST command, sending data */ + HTTP_PUT, /* PUT command, waiting for blank line */ + HTTP_PUT_RECV, /* PUT command, receiving data */ + HTTP_DELETE, /* DELETE command, waiting for blank line */ + HTTP_TRACE, /* TRACE command, waiting for blank line */ + HTTP_CLOSE, /* CLOSE command, waiting for blank line */ + HTTP_STATUS /* Command complete, sending status */ +} http_state_t; + + +/* + * HTTP version numbers... + */ + +typedef enum +{ + HTTP_0_9 = 9, /* HTTP/0.9 */ + HTTP_1_0 = 100, /* HTTP/1.0 */ + HTTP_1_1 = 101 /* HTTP/1.1 */ +} http_version_t; + + +/* + * HTTP keep-alive values... + */ + +typedef enum +{ + HTTP_KEEPALIVE_OFF = 0, + HTTP_KEEPALIVE_ON +} http_keepalive_t; + + +/* + * HTTP transfer encoding values... + */ + +typedef enum +{ + HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */ + HTTP_ENCODE_CHUNKED /* Data is chunked */ +} http_encoding_t; + + +/* + * HTTP encryption values... + */ + +typedef enum +{ + HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */ + HTTP_ENCRYPT_NEVER, /* Never encrypt */ + HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */ + HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */ +} http_encryption_t; + + +/* + * HTTP authentication types... + */ + +typedef enum +{ + HTTP_AUTH_NONE, /* No authentication in use */ + HTTP_AUTH_BASIC, /* Basic authentication in use */ + HTTP_AUTH_MD5, /* Digest authentication in use */ + HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ + HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ + HTTP_AUTH_MD5_SESS_INT /* MD5-session authentication in use for body */ +} http_auth_t; + + +/* + * HTTP status codes... + */ + +typedef enum +{ + HTTP_ERROR = -1, /* An error response from httpXxxx() */ + + HTTP_CONTINUE = 100, /* Everything OK, keep going... */ + HTTP_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */ + + HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ + HTTP_CREATED, /* PUT command was successful */ + HTTP_ACCEPTED, /* DELETE command was successful */ + HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */ + HTTP_NO_CONTENT, /* Successful command, no new data */ + HTTP_RESET_CONTENT, /* Content was reset/recreated */ + HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */ + + HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */ + HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */ + HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */ + HTTP_SEE_OTHER, /* See this other link... */ + HTTP_NOT_MODIFIED, /* File not modified */ + HTTP_USE_PROXY, /* Must use a proxy to access this URI */ + + HTTP_BAD_REQUEST = 400, /* Bad request */ + HTTP_UNAUTHORIZED, /* Unauthorized to access host */ + HTTP_PAYMENT_REQUIRED, /* Payment required */ + HTTP_FORBIDDEN, /* Forbidden to access this URI */ + HTTP_NOT_FOUND, /* URI was not found */ + HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */ + HTTP_NOT_ACCEPTABLE, /* Not Acceptable */ + HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ + HTTP_REQUEST_TIMEOUT, /* Request timed out */ + HTTP_CONFLICT, /* Request is self-conflicting */ + HTTP_GONE, /* Server has gone away */ + HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */ + HTTP_PRECONDITION, /* Precondition failed */ + HTTP_REQUEST_TOO_LARGE, /* Request entity too large */ + HTTP_URI_TOO_LONG, /* URI too long */ + HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ + HTTP_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */ + + HTTP_SERVER_ERROR = 500, /* Internal server error */ + HTTP_NOT_IMPLEMENTED, /* Feature not implemented */ + HTTP_BAD_GATEWAY, /* Bad gateway */ + HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */ + HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */ + HTTP_NOT_SUPPORTED /* HTTP version not supported */ +} http_status_t; + + +/* + * HTTP field names... + */ + +typedef enum +{ + HTTP_FIELD_UNKNOWN = -1, + HTTP_FIELD_ACCEPT_LANGUAGE, + HTTP_FIELD_ACCEPT_RANGES, + HTTP_FIELD_AUTHORIZATION, + HTTP_FIELD_CONNECTION, + HTTP_FIELD_CONTENT_ENCODING, + HTTP_FIELD_CONTENT_LANGUAGE, + HTTP_FIELD_CONTENT_LENGTH, + HTTP_FIELD_CONTENT_LOCATION, + HTTP_FIELD_CONTENT_MD5, + HTTP_FIELD_CONTENT_RANGE, + HTTP_FIELD_CONTENT_TYPE, + HTTP_FIELD_CONTENT_VERSION, + HTTP_FIELD_DATE, + HTTP_FIELD_HOST, + HTTP_FIELD_IF_MODIFIED_SINCE, + HTTP_FIELD_IF_UNMODIFIED_SINCE, + HTTP_FIELD_KEEP_ALIVE, + HTTP_FIELD_LAST_MODIFIED, + HTTP_FIELD_LINK, + HTTP_FIELD_LOCATION, + HTTP_FIELD_RANGE, + HTTP_FIELD_REFERER, + HTTP_FIELD_RETRY_AFTER, + HTTP_FIELD_TRANSFER_ENCODING, + HTTP_FIELD_UPGRADE, + HTTP_FIELD_USER_AGENT, + HTTP_FIELD_WWW_AUTHENTICATE, + HTTP_FIELD_MAX +} http_field_t; + + +/* + * HTTP connection structure... + */ + +typedef struct +{ + int fd; /* File descriptor for this socket */ + int blocking; /* To block or not to block */ + int error; /* Last error on read */ + time_t activity; /* Time since last read/write */ + http_state_t state; /* State of client */ + http_status_t status; /* Status of last request */ + http_version_t version; /* Protocol version */ + http_keepalive_t keep_alive; /* Keep-alive supported? */ + struct sockaddr_in hostaddr; /* Address of connected host */ + char hostname[HTTP_MAX_HOST], + /* Name of connected host */ + fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE]; + /* Field values */ + char *data; /* Pointer to data buffer */ + http_encoding_t data_encoding; /* Chunked or not */ + int data_remaining; /* Number of bytes left */ + int used; /* Number of bytes used in buffer */ + char buffer[HTTP_MAX_BUFFER]; + /* Buffer for messages */ + int auth_type; /* Authentication in use */ + md5_state_t md5_state; /* MD5 state */ + char nonce[HTTP_MAX_VALUE]; + /* Nonce value */ + int nonce_count; /* Nonce count */ + void *tls; /* TLS state information */ + http_encryption_t encryption; /* Encryption requirements */ +} http_t; + + +/* + * Prototypes... + */ + +# define httpBlocking(http,b) (http)->blocking = (b) +extern int httpCheck(http_t *http); +# define httpClearFields(http) memset((http)->fields, 0, sizeof((http)->fields)),\ + httpSetField((http), HTTP_FIELD_HOST, (http)->hostname) +extern void httpClose(http_t *http); +extern http_t *httpConnect(const char *host, int port); +extern int httpDelete(http_t *http, const char *uri); +extern int httpEncryption(http_t *http, http_encryption_t e); +# define httpError(http) ((http)->error) +extern void httpFlush(http_t *http); +extern int httpGet(http_t *http, const char *uri); +extern char *httpGets(char *line, int length, http_t *http); +extern const char *httpGetDateString(time_t t); +extern time_t httpGetDateTime(const char *s); +# define httpGetField(http,field) (http)->fields[field] +extern char *httpGetSubField(http_t *http, http_field_t field, + const char *name, char *value); +extern int httpHead(http_t *http, const char *uri); +extern void httpInitialize(void); +extern int httpOptions(http_t *http, const char *uri); +extern int httpPost(http_t *http, const char *uri); +extern int httpPrintf(http_t *http, const char *format, ...); +extern int httpPut(http_t *http, const char *uri); +extern int httpRead(http_t *http, char *buffer, int length); +extern int httpReconnect(http_t *http); +extern void httpSeparate(const char *uri, char *method, + char *username, char *host, int *port, + char *resource); +extern void httpSetField(http_t *http, http_field_t field, + const char *value); +extern const char *httpStatus(http_status_t status); +extern int httpTrace(http_t *http, const char *uri); +extern http_status_t httpUpdate(http_t *http); +extern int httpWrite(http_t *http, const char *buffer, int length); +extern char *httpEncode64(char *out, const char *in); +extern char *httpDecode64(char *out, const char *in); +extern int httpGetLength(http_t *http); +extern char *httpMD5(const char *, const char *, const char *, + char [33]); +extern char *httpMD5Final(const char *, const char *, const char *, + char [33]); +extern char *httpMD5String(const md5_byte_t *, char [33]); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_HTTP_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/ipp.c b/cups/ipp.c new file mode 100644 index 0000000000..75b91ba8bb --- /dev/null +++ b/cups/ipp.c @@ -0,0 +1,1874 @@ +/* + * "$Id$" + * + * Internet Printing Protocol support functions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ippAddBoolean() - Add a boolean attribute to an IPP request. + * ippAddBooleans() - Add an array of boolean values. + * ippAddDate() - Add a date attribute to an IPP request. + * ippAddInteger() - Add a integer attribute to an IPP request. + * ippAddIntegers() - Add an array of integer values. + * ippAddString() - Add a language-encoded string to an IPP request. + * ippAddStrings() - Add language-encoded strings to an IPP request. + * ippAddRange() - Add a range of values to an IPP request. + * ippAddRanges() - Add ranges of values to an IPP request. + * ippAddResolution() - Add a resolution value to an IPP request. + * ippAddResolutions() - Add resolution values to an IPP request. + * ippAddSeparator() - Add a group separator to an IPP request. + * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX time + * ippDelete() - Delete an IPP request. + * ippErrorString() - Return a textual message for the given error message. + * ippFindAttribute() - Find a named attribute in a request... + * ippLength() - Compute the length of an IPP request. + * ippNew() - Allocate a new IPP request. + * ippPort() - Return the default IPP port number. + * ippRead() - Read data for an IPP request. + * ippSetPort() - Set the default port number. + * ippTimeToDate() - Convert from UNIX time to RFC 1903 format. + * ippWrite() - Write data for an IPP request. + * _ipp_add_attr() - Add a new attribute to the request. + * _ipp_free_attr() - Free an attribute. + * ipp_read() - Semi-blocking read on a HTTP connection... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "string.h" +#include "language.h" + +#include "ipp.h" +#include "debug.h" +#include + + +/* + * Local globals... + */ + +static int ipp_port = 0; + + +/* + * Local functions... + */ + +static int ipp_read(http_t *http, unsigned char *buffer, int length); + + +/* + * 'ippAddBoolean()' - Add a boolean attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddBoolean(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + char value) /* I - Value of attribute */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddBoolean(%p, %02x, \'%s\', %d)\n", ipp, group, name, value)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_BOOLEAN; + attr->values[0].boolean = value; + + return (attr); +} + + +/* + * 'ippAddBooleans()' - Add an array of boolean values. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddBooleans(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const char *values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\n", ipp, + group, name, num_values, values)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_BOOLEAN; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + attr->values[i].boolean = values[i]; + + return (attr); +} + + +/* + * 'ippAddDate()' - Add a date attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddDate(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + const ipp_uchar_t *value) /* I - Value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddDate(%p, %02x, \'%s\', %p)\n", ipp, group, name, + value)); + + if (ipp == NULL || name == NULL || value == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_DATE; + memcpy(attr->values[0].date, value, 11); + + return (attr); +} + + +/* + * 'ippAddInteger()' - Add a integer attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddInteger(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int value) /* I - Value of attribute */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddInteger(%p, %d, \'%s\', %d)\n", ipp, group, name, + value)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + attr->values[0].integer = value; + + return (attr); +} + + +/* + * 'ippAddIntegers()' - Add an array of integer values. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddIntegers(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const int *values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + attr->values[i].integer = values[i]; + + return (attr); +} + + +/* + * 'ippAddString()' - Add a language-encoded string to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddString(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + const char *charset, /* I - Character set */ + const char *value) /* I - Value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + attr->values[0].string.charset = charset ? strdup(charset) : NULL; + attr->values[0].string.text = value ? strdup(value) : NULL; + + if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && + attr->values[0].string.text) + { + /* + * Convert to lowercase and change _ to - as needed... + */ + + char *p; + + + for (p = attr->values[0].string.text; *p; p ++) + if (*p == '_') + *p = '-'; + else + *p = tolower(*p); + } + + return (attr); +} + + +/* + * 'ippAddStrings()' - Add language-encoded strings to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddStrings(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const char *charset, /* I - Character set */ + const char **values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + { + if (i == 0) + attr->values[0].string.charset = charset ? strdup(charset) : NULL; + else + attr->values[i].string.charset = attr->values[0].string.charset; + + attr->values[i].string.text = strdup(values[i]); + } + + return (attr); +} + + +/* + * 'ippAddRange()' - Add a range of values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRange(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int lower, /* I - Lower value */ + int upper) /* I - Upper value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RANGE; + attr->values[0].range.lower = lower; + attr->values[0].range.upper = upper; + + return (attr); +} + + +/* + * 'ippAddRanges()' - Add ranges of values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRanges(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const int *lower, /* I - Lower values */ + const int *upper) /* I - Upper values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RANGE; + + if (lower != NULL && upper != NULL) + for (i = 0; i < num_values; i ++) + { + attr->values[i].range.lower = lower[i]; + attr->values[i].range.upper = upper[i]; + } + + return (attr); +} + + +/* + * 'ippAddResolution()' - Add a resolution value to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolution(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + ipp_res_t units, /* I - Units for resolution */ + int xres, /* I - X resolution */ + int yres) /* I - Y resolution */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RESOLUTION; + attr->values[0].resolution.xres = xres; + attr->values[0].resolution.yres = yres; + attr->values[0].resolution.units = units; + + return (attr); +} + + +/* + * 'ippAddResolutions()' - Add resolution values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolutions(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values,/* I - Number of values */ + ipp_res_t units, /* I - Units for resolution */ + const int *xres, /* I - X resolutions */ + const int *yres) /* I - Y resolutions */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RESOLUTION; + + if (xres != NULL && yres != NULL) + for (i = 0; i < num_values; i ++) + { + attr->values[i].resolution.xres = xres[i]; + attr->values[i].resolution.yres = yres[i]; + attr->values[i].resolution.units = units; + } + + return (attr); +} + + +/* + * 'ippAddSeparator()' - Add a group separator to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddSeparator(ipp_t *ipp) /* I - IPP request */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddSeparator(%p)\n", ipp)); + + if (ipp == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 0)) == NULL) + return (NULL); + + attr->group_tag = IPP_TAG_ZERO; + attr->value_tag = IPP_TAG_ZERO; + + return (attr); +} + + +/* + * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time + * in seconds. + */ + +time_t /* O - UNIX time value */ +ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */ +{ + struct tm unixdate; /* UNIX date/time info */ + time_t t; /* Computed time */ + + + memset(&unixdate, 0, sizeof(unixdate)); + + /* + * RFC-1903 date/time format is: + * + * Byte(s) Description + * ------- ----------- + * 0-1 Year (0 to 65535) + * 2 Month (1 to 12) + * 3 Day (1 to 31) + * 4 Hours (0 to 23) + * 5 Minutes (0 to 59) + * 6 Seconds (0 to 60, 60 = "leap second") + * 7 Deciseconds (0 to 9) + * 8 +/- UTC + * 9 UTC hours (0 to 11) + * 10 UTC minutes (0 to 59) + */ + + unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900; + unixdate.tm_mon = date[2] - 1; + unixdate.tm_mday = date[3]; + unixdate.tm_hour = date[4]; + unixdate.tm_min = date[5]; + unixdate.tm_sec = date[6]; + + t = mktime(&unixdate); + + if (date[8] == '-') + t += date[9] * 3600 + date[10] * 60; + else + t -= date[9] * 3600 + date[10] * 60; + + return (t); +} + + +/* + * 'ippDelete()' - Delete an IPP request. + */ + +void +ippDelete(ipp_t *ipp) /* I - IPP request */ +{ + ipp_attribute_t *attr, /* Current attribute */ + *next; /* Next attribute */ + + + DEBUG_printf(("ippNew(): %p\n", ipp)); + + if (ipp == NULL) + return; + + for (attr = ipp->attrs; attr != NULL; attr = next) + { + next = attr->next; + _ipp_free_attr(attr); + } + + free(ipp); +} + + +/* + * 'ippErrorString()' - Return a textual message for the given error message. + */ + +const char * /* O - Text string */ +ippErrorString(ipp_status_t error) /* I - Error status */ +{ + static char unknown[255]; /* Unknown error statuses */ + static const char *status_oks[] = /* "OK" status codes */ + { + "successful-ok", + "successful-ok-ignored-or-substituted-attributes", + "successful-ok-conflicting-attributes", + "successful-ok-ignored-subscriptions", + "successful-ok-ignored-notifications", + "successful-ok-too-many-events", + "successful-ok-but-cancel-subscription" + }, + *status_400s[] = /* Client errors */ + { + "client-error-bad-request", + "client-error-forbidden", + "client-error-not-authenticated", + "client-error-not-authorized", + "client-error-not-possible", + "client-error-timeout", + "client-error-not-found", + "client-error-gone", + "client-error-request-entity-too-large", + "client-error-request-value-too-long", + "client-error-document-format-not-supported", + "client-error-attributes-or-values-not-supported", + "client-error-uri-scheme-not-supported", + "client-error-charset-not-supported", + "client-error-conflicting-attributes", + "client-error-compression-not-supported", + "client-error-compression-error", + "client-error-document-format-error", + "client-error-document-access-error", + "client-error-attributes-not-settable", + "client-error-ignored-all-subscriptions", + "client-error-too-many-subscriptions", + "client-error-ignored-all-notifications", + "client-error-print-support-file-not-found" + }, + *status_500s[] = /* Server errors */ + { + "server-error-internal-error", + "server-error-operation-not-supported", + "server-error-service-unavailable", + "server-error-version-not-supported", + "server-error-device-error", + "server-error-temporary-error", + "server-error-not-accepting-jobs", + "server-error-busy", + "server-error-job-canceled", + "server-error-multiple-document-jobs-not-supported", + "server-error-printer-is-deactivated" + }; + + + /* + * See if the error code is a known value... + */ + + if (error >= IPP_OK && error <= IPP_OK_BUT_CANCEL_SUBSCRIPTION) + return (status_oks[error]); + else if (error == IPP_REDIRECTION_OTHER_SITE) + return ("redirection-other-site"); + else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND) + return (status_400s[error - IPP_BAD_REQUEST]); + else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED) + return (status_500s[error - IPP_INTERNAL_ERROR]); + + /* + * No, build an "unknown-xxxx" error string... + */ + + sprintf(unknown, "unknown-%04x", error); + + return (unknown); +} + + +/* + * 'ippFindAttribute()' - Find a named attribute in a request... + */ + +ipp_attribute_t * /* O - Matching attribute */ +ippFindAttribute(ipp_t *ipp, /* I - IPP request */ + const char *name, /* I - Name of attribute */ + ipp_tag_t type) /* I - Type of attribute */ +{ + ipp_attribute_t *attr; /* Current atttribute */ + ipp_tag_t value_tag; /* Value tag */ + + + DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp, name)); + + if (ipp == NULL || name == NULL) + return (NULL); + + for (attr = ipp->attrs; attr != NULL; attr = attr->next) + { + DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr, + attr->name)); + + value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK); + + if (attr->name != NULL && strcasecmp(attr->name, name) == 0 && + (value_tag == type || type == IPP_TAG_ZERO || + (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) || + (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME))) + return (attr); + } + + return (NULL); +} + + +/* + * 'ippLength()' - Compute the length of an IPP request. + */ + +size_t /* O - Size of IPP request */ +ippLength(ipp_t *ipp) /* I - IPP request */ +{ + int i; /* Looping var */ + int bytes; /* Number of bytes */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t group; /* Current group */ + + + if (ipp == NULL) + return (0); + + /* + * Start with 8 bytes for the IPP request or status header... + */ + + bytes = 8; + + /* + * Then add the lengths of each attribute... + */ + + group = IPP_TAG_ZERO; + + for (attr = ipp->attrs; attr != NULL; attr = attr->next) + { + if (attr->group_tag != group) + { + group = attr->group_tag; + if (group == IPP_TAG_ZERO) + continue; + + bytes ++; /* Group tag */ + } + + DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n", + attr->name, attr->num_values, bytes)); + + bytes += strlen(attr->name); /* Name */ + bytes += attr->num_values; /* Value tag for each value */ + bytes += 2 * attr->num_values; /* Name lengths */ + bytes += 2 * attr->num_values; /* Value lengths */ + + switch (attr->value_tag & ~IPP_TAG_COPY) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + bytes += 4 * attr->num_values; + break; + + case IPP_TAG_BOOLEAN : + bytes += attr->num_values; + break; + + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + for (i = 0; i < attr->num_values; i ++) + bytes += strlen(attr->values[i].string.text); + break; + + case IPP_TAG_DATE : + bytes += 11 * attr->num_values; + break; + + case IPP_TAG_RESOLUTION : + bytes += 9 * attr->num_values; + break; + + case IPP_TAG_RANGE : + bytes += 8 * attr->num_values; + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + bytes += 4 * attr->num_values;/* Charset + text length */ + for (i = 0; i < attr->num_values; i ++) + bytes += strlen(attr->values[i].string.charset) + + strlen(attr->values[i].string.text); + break; + + default : + for (i = 0; i < attr->num_values; i ++) + bytes += attr->values[0].unknown.length; + break; + } + } + + /* + * Finally, add 1 byte for the "end of attributes" tag and return... + */ + + DEBUG_printf(("bytes = %d\n", bytes + 1)); + + return (bytes + 1); +} + + +/* + * 'ippNew()' - Allocate a new IPP request. + */ + +ipp_t * /* O - New IPP request */ +ippNew(void) +{ + ipp_t *temp; /* New IPP request */ + + + if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL) + { + /* + * Default to IPP 1.1... + */ + + temp->request.any.version[0] = 1; + temp->request.any.version[1] = 1; + } + + DEBUG_printf(("ippNew(): %p\n", temp)); + + return (temp); +} + + +/* + * 'ippRead()' - Read data for an IPP request. + */ + +ipp_state_t /* O - Current state */ +ippRead(http_t *http, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + int n; /* Length of data */ + unsigned char buffer[8192], /* Data buffer */ + *bufptr; /* Pointer into buffer */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t tag; /* Current tag */ + + + DEBUG_printf(("ippRead(%p, %p)\n", http, ipp)); + + if (http == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Get the request header... + */ + + if ((n = ipp_read(http, buffer, 8)) < 8) + { + DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n)); + return (n == 0 ? IPP_IDLE : IPP_ERROR); + } + + /* + * Verify the major version number... + */ + + if (buffer[0] != 1) + { + DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer[0], + buffer[1])); + return (IPP_ERROR); + } + + /* + * Then copy the request header over... + */ + + ipp->request.any.version[0] = buffer[0]; + ipp->request.any.version[1] = buffer[1]; + ipp->request.any.op_status = (buffer[2] << 8) | buffer[3]; + ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) | + buffer[6]) << 8) | buffer[7]; + + ipp->state = IPP_ATTRIBUTE; + ipp->current = NULL; + ipp->curtag = IPP_TAG_ZERO; + + DEBUG_printf(("ippRead: version=%d.%d\n", buffer[0], buffer[1])); + DEBUG_printf(("ippRead: op_status=%04x\n", ipp->request.any.op_status)); + DEBUG_printf(("ippRead: request_id=%d\n", ipp->request.any.request_id)); + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking && http->used == 0) + break; + + case IPP_ATTRIBUTE : + while (ipp_read(http, buffer, 1) > 0) + { + /* + * Read this attribute... + */ + + tag = (ipp_tag_t)buffer[0]; + + if (tag == IPP_TAG_END) + { + /* + * No more attributes left... + */ + + DEBUG_puts("ippRead: IPP_TAG_END!"); + + ipp->state = IPP_DATA; + break; + } + else if (tag < IPP_TAG_UNSUPPORTED_VALUE) + { + /* + * Group tag... Set the current group and continue... + */ + + if (ipp->curtag == tag) + ippAddSeparator(ipp); + + ipp->curtag = tag; + ipp->current = NULL; + DEBUG_printf(("ippRead: group tag = %x\n", tag)); + continue; + } + + DEBUG_printf(("ippRead: value tag = %x\n", tag)); + + /* + * Get the name... + */ + + if (ipp_read(http, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read name length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + + DEBUG_printf(("ippRead: name length = %d\n", n)); + + if (n == 0) + { + /* + * More values for current attribute... + */ + + if (ipp->current == NULL) + return (IPP_ERROR); + + attr = ipp->current; + + /* + * Make sure we aren't adding a new value of a different + * type... + */ + + if (attr->value_tag == IPP_TAG_STRING || + (attr->value_tag >= IPP_TAG_TEXTLANG && + attr->value_tag <= IPP_TAG_MIMETYPE)) + { + /* + * String values can sometimes come across in different + * forms; accept sets of differing values... + */ + + if (tag != IPP_TAG_STRING && + (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE)) + return (IPP_ERROR); + } + else if (attr->value_tag != tag) + return (IPP_ERROR); + + /* + * Finally, make sure we don't have too many elements in the + * attribute array... + */ + + if (attr->num_values >= IPP_MAX_VALUES) + return (IPP_ERROR); + } + else + { + /* + * New attribute; read the name and add it... + */ + + if (ipp_read(http, buffer, n) < n) + { + DEBUG_puts("ippRead: unable to read name!"); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: name = \'%s\'\n", buffer)); + + attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES); + + attr->group_tag = ipp->curtag; + attr->value_tag = tag; + attr->name = strdup((char *)buffer); + attr->num_values = 0; + } + + if (ipp_read(http, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read value length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + DEBUG_printf(("ippRead: value length = %d\n", n)); + + switch (tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (ipp_read(http, buffer, 4) < 4) + return (IPP_ERROR); + + n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + + attr->values[attr->num_values].integer = n; + break; + case IPP_TAG_BOOLEAN : + if (ipp_read(http, buffer, 1) < 1) + return (IPP_ERROR); + + attr->values[attr->num_values].boolean = buffer[0]; + break; + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + if (ipp_read(http, buffer, n) < n) + return (IPP_ERROR); + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: value = \'%s\'\n", buffer)); + + attr->values[attr->num_values].string.text = strdup((char *)buffer); + break; + case IPP_TAG_DATE : + if (ipp_read(http, buffer, 11) < 11) + return (IPP_ERROR); + + memcpy(attr->values[attr->num_values].date, buffer, 11); + break; + case IPP_TAG_RESOLUTION : + if (ipp_read(http, buffer, 9) < 9) + return (IPP_ERROR); + + attr->values[attr->num_values].resolution.xres = + (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + attr->values[attr->num_values].resolution.yres = + (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | + buffer[7]; + attr->values[attr->num_values].resolution.units = + (ipp_res_t)buffer[8]; + break; + case IPP_TAG_RANGE : + if (ipp_read(http, buffer, 8) < 8) + return (IPP_ERROR); + + attr->values[attr->num_values].range.lower = + (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + attr->values[attr->num_values].range.upper = + (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | + buffer[7]; + break; + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + if (ipp_read(http, buffer, n) < n) + return (IPP_ERROR); + + bufptr = buffer; + + /* + * text-with-language and name-with-language are composite + * values: + * + * charset-length + * charset + * text-length + * text + */ + + n = (bufptr[0] << 8) | bufptr[1]; + + attr->values[attr->num_values].string.charset = calloc(n + 1, 1); + + memcpy(attr->values[attr->num_values].string.charset, + bufptr + 2, n); + + bufptr += 2 + n; + n = (bufptr[0] << 8) | bufptr[1]; + + attr->values[attr->num_values].string.text = calloc(n + 1, 1); + + memcpy(attr->values[attr->num_values].string.text, + bufptr + 2, n); + + break; + + default : /* Other unsupported values */ + attr->values[attr->num_values].unknown.length = n; + if (n > 0) + { + attr->values[attr->num_values].unknown.data = malloc(n); + if (ipp_read(http, attr->values[attr->num_values].unknown.data, n) < n) + return (IPP_ERROR); + } + else + attr->values[attr->num_values].unknown.data = NULL; + break; + } + + attr->num_values ++; + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking && http->used == 0) + break; + } + break; + + case IPP_DATA : + break; + + default : + break; /* anti-compiler-warning-code */ + } + + return (ipp->state); +} + + +/* + * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format. + */ + +const ipp_uchar_t * /* O - RFC-1903 date/time data */ +ippTimeToDate(time_t t) /* I - UNIX time value */ +{ + struct tm *unixdate; /* UNIX unixdate/time info */ + static ipp_uchar_t date[11]; /* RFC-1903 date/time data */ + + + /* + * RFC-1903 date/time format is: + * + * Byte(s) Description + * ------- ----------- + * 0-1 Year (0 to 65535) + * 2 Month (1 to 12) + * 3 Day (1 to 31) + * 4 Hours (0 to 23) + * 5 Minutes (0 to 59) + * 6 Seconds (0 to 60, 60 = "leap second") + * 7 Deciseconds (0 to 9) + * 8 +/- UTC + * 9 UTC hours (0 to 11) + * 10 UTC minutes (0 to 59) + */ + + unixdate = gmtime(&t); + unixdate->tm_year += 1900; + + date[0] = unixdate->tm_year >> 8; + date[1] = unixdate->tm_year; + date[2] = unixdate->tm_mon + 1; + date[3] = unixdate->tm_mday; + date[4] = unixdate->tm_hour; + date[5] = unixdate->tm_min; + date[6] = unixdate->tm_sec; + date[7] = 0; + date[8] = '+'; + date[9] = 0; + date[10] = 0; + + return (date); +} + + +/* + * 'ippWrite()' - Write data for an IPP request. + */ + +ipp_state_t /* O - Current state */ +ippWrite(http_t *http, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + int i; /* Looping var */ + int n; /* Length of data */ + unsigned char buffer[8192], /* Data buffer */ + *bufptr; /* Pointer into buffer */ + ipp_attribute_t *attr; /* Current attribute */ + + + if (http == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Send the request header... + */ + + bufptr = buffer; + + *bufptr++ = ipp->request.any.version[0]; + *bufptr++ = ipp->request.any.version[1]; + *bufptr++ = ipp->request.any.op_status >> 8; + *bufptr++ = ipp->request.any.op_status; + *bufptr++ = ipp->request.any.request_id >> 24; + *bufptr++ = ipp->request.any.request_id >> 16; + *bufptr++ = ipp->request.any.request_id >> 8; + *bufptr++ = ipp->request.any.request_id; + + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP header..."); + return (IPP_ERROR); + } + + ipp->state = IPP_ATTRIBUTE; + ipp->current = ipp->attrs; + ipp->curtag = IPP_TAG_ZERO; + + DEBUG_printf(("ippWrite: version=%d.%d\n", buffer[0], buffer[1])); + DEBUG_printf(("ippWrite: op_status=%04x\n", ipp->request.any.op_status)); + DEBUG_printf(("ippWrite: request_id=%d\n", ipp->request.any.request_id)); + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking) + break; + + case IPP_ATTRIBUTE : + while (ipp->current != NULL) + { + /* + * Write this attribute... + */ + + bufptr = buffer; + attr = ipp->current; + + ipp->current = ipp->current->next; + + if (ipp->curtag != attr->group_tag) + { + /* + * Send a group operation tag... + */ + + ipp->curtag = attr->group_tag; + + if (attr->group_tag == IPP_TAG_ZERO) + continue; + + DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr->group_tag)); + *bufptr++ = attr->group_tag; + } + + if ((n = strlen(attr->name)) > (sizeof(buffer) - 3)) + return (IPP_ERROR); + + DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag)); + DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name)); + + *bufptr++ = attr->value_tag; + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->name, n); + bufptr += n; + + switch (attr->value_tag & ~IPP_TAG_COPY) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + for (i = 0; i < attr->num_values; i ++) + { + if ((sizeof(buffer) - (bufptr - buffer)) < 9) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 4; + *bufptr++ = attr->values[i].integer >> 24; + *bufptr++ = attr->values[i].integer >> 16; + *bufptr++ = attr->values[i].integer >> 8; + *bufptr++ = attr->values[i].integer; + } + break; + + case IPP_TAG_BOOLEAN : + for (i = 0; i < attr->num_values; i ++) + { + if ((sizeof(buffer) - (bufptr - buffer)) < 6) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 1; + *bufptr++ = attr->values[i].boolean; + } + break; + + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + DEBUG_printf(("ippWrite: writing value tag = %x\n", + attr->value_tag)); + DEBUG_printf(("ippWrite: writing name = 0, \'\'\n")); + + if ((sizeof(buffer) - (bufptr - buffer)) < 3) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.text); + + if (n > sizeof(buffer)) + return (IPP_ERROR); + + DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n, + attr->values[i].string.text)); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + + case IPP_TAG_DATE : + for (i = 0; i < attr->num_values; i ++) + { + if ((sizeof(buffer) - (bufptr - buffer)) < 16) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 11; + memcpy(bufptr, attr->values[i].date, 11); + bufptr += 11; + } + break; + + case IPP_TAG_RESOLUTION : + for (i = 0; i < attr->num_values; i ++) + { + if ((sizeof(buffer) - (bufptr - buffer)) < 14) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 9; + *bufptr++ = attr->values[i].resolution.xres >> 24; + *bufptr++ = attr->values[i].resolution.xres >> 16; + *bufptr++ = attr->values[i].resolution.xres >> 8; + *bufptr++ = attr->values[i].resolution.xres; + *bufptr++ = attr->values[i].resolution.yres >> 24; + *bufptr++ = attr->values[i].resolution.yres >> 16; + *bufptr++ = attr->values[i].resolution.yres >> 8; + *bufptr++ = attr->values[i].resolution.yres; + *bufptr++ = attr->values[i].resolution.units; + } + break; + + case IPP_TAG_RANGE : + for (i = 0; i < attr->num_values; i ++) + { + if ((sizeof(buffer) - (bufptr - buffer)) < 13) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + *bufptr++ = 0; + *bufptr++ = 8; + *bufptr++ = attr->values[i].range.lower >> 24; + *bufptr++ = attr->values[i].range.lower >> 16; + *bufptr++ = attr->values[i].range.lower >> 8; + *bufptr++ = attr->values[i].range.lower; + *bufptr++ = attr->values[i].range.upper >> 24; + *bufptr++ = attr->values[i].range.upper >> 16; + *bufptr++ = attr->values[i].range.upper >> 8; + *bufptr++ = attr->values[i].range.upper; + } + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + if ((sizeof(buffer) - (bufptr - buffer)) < 3) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.charset) + + strlen(attr->values[i].string.text) + + 4; + + if (n > sizeof(buffer)) + return (IPP_ERROR); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + /* Length of entire value */ + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Length of charset */ + n = strlen(attr->values[i].string.charset); + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Charset */ + memcpy(bufptr, attr->values[i].string.charset, n); + bufptr += n; + + /* Length of text */ + n = strlen(attr->values[i].string.text); + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Text */ + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + + default : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + if ((sizeof(buffer) - (bufptr - buffer)) < 3) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = attr->values[i].unknown.length; + + if (n > sizeof(buffer)) + return (IPP_ERROR); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + /* Length of unknown value */ + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Value */ + if (n > 0) + { + memcpy(bufptr, attr->values[i].unknown.data, n); + bufptr += n; + } + } + break; + } + + /* + * Write the data out... + */ + + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer)); + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking) + break; + } + + if (ipp->current == NULL) + { + /* + * Done with all of the attributes; add the end-of-attributes tag... + */ + + buffer[0] = IPP_TAG_END; + if (httpWrite(http, (char *)buffer, 1) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP end-tag..."); + return (IPP_ERROR); + } + + ipp->state = IPP_DATA; + } + break; + + case IPP_DATA : + break; + + default : + break; /* anti-compiler-warning-code */ + } + + return (ipp->state); +} + + +/* + * 'ippPort()' - Return the default IPP port number. + */ + +int /* O - Port number */ +ippPort(void) +{ + const char *server_port; /* SERVER_PORT environment variable */ + struct servent *port; /* Port number info */ + + + if (ipp_port) + return (ipp_port); + else if ((server_port = getenv("IPP_PORT")) != NULL) + return (ipp_port = atoi(server_port)); + else if ((port = getservbyname("ipp", NULL)) == NULL) + return (ipp_port = IPP_PORT); + else + return (ipp_port = ntohs(port->s_port)); +} + + +/* + * 'ippSetPort()' - Set the default port number. + */ + +void +ippSetPort(int p) /* I - Port number to use */ +{ + ipp_port = p; +} + + +/* + * '_ipp_add_attr()' - Add a new attribute to the request. + */ + +ipp_attribute_t * /* O - New attribute */ +_ipp_add_attr(ipp_t *ipp, /* I - IPP request */ + int num_values) /* I - Number of values */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("_ipp_add_attr(%p, %d)\n", ipp, num_values)); + + if (ipp == NULL || num_values < 0) + return (NULL); + + attr = calloc(sizeof(ipp_attribute_t) + + (num_values - 1) * sizeof(ipp_value_t), 1); + + attr->num_values = num_values; + + if (attr == NULL) + return (NULL); + + if (ipp->last == NULL) + ipp->attrs = attr; + else + ipp->last->next = attr; + + ipp->last = attr; + + DEBUG_printf(("_ipp_add_attr(): %p\n", attr)); + + return (attr); +} + + +/* + * '_ipp_free_attr()' - Free an attribute. + */ + +void +_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */ +{ + int i; /* Looping var */ + + + DEBUG_printf(("_ipp_free_attr(): %p\n", attr)); + + switch (attr->value_tag) + { + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_STRING : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + for (i = 0; i < attr->num_values; i ++) + free(attr->values[i].string.text); + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + for (i = 0; i < attr->num_values; i ++) + { + if (attr->values[i].string.charset && i == 0) + free(attr->values[i].string.charset); + free(attr->values[i].string.text); + } + break; + + default : + break; /* anti-compiler-warning-code */ + } + + if (attr->name != NULL) + free(attr->name); + + free(attr); +} + + +/* + * 'ipp_read()' - Semi-blocking read on a HTTP connection... + */ + +static int /* O - Number of bytes read */ +ipp_read(http_t *http, /* I - Client connection */ + unsigned char *buffer, /* O - Buffer for data */ + int length) /* I - Total length */ +{ + int tbytes, /* Total bytes read */ + bytes; /* Bytes read this pass */ + + + /* + * Loop until all bytes are read... + */ + + for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes) + if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0) + break; + + /* + * Return the number of bytes read... + */ + + if (tbytes == 0 && bytes < 0) + return (-1); + else + return (tbytes); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ipp.h b/cups/ipp.h new file mode 100644 index 0000000000..c8715148f7 --- /dev/null +++ b/cups/ipp.h @@ -0,0 +1,430 @@ +/* + * "$Id$" + * + * Internet Printing Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_IPP_H_ +# define _CUPS_IPP_H_ + +/* + * Include necessary headers... + */ + +# include "http.h" + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * IPP version string... + */ + +# define IPP_VERSION "\001\000" + +/* + * IPP registered port number... This is the default value - applications + * should use the ippPort() function so that you can customize things in + * /etc/services if needed! + */ + +# define IPP_PORT 631 + +/* + * Common limits... + */ + +# define IPP_MAX_NAME 256 +# define IPP_MAX_VALUES 100 + + +/* + * Types and structures... + */ + +typedef enum /**** Format tags for attribute formats... ****/ +{ + IPP_TAG_ZERO = 0x00, + IPP_TAG_OPERATION, + IPP_TAG_JOB, + IPP_TAG_END, + IPP_TAG_PRINTER, + IPP_TAG_UNSUPPORTED_GROUP, + IPP_TAG_SUBSCRIPTION, + IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_UNSUPPORTED_VALUE = 0x10, + IPP_TAG_DEFAULT, + IPP_TAG_UNKNOWN, + IPP_TAG_NOVALUE, + IPP_TAG_NOTSETTABLE = 0x15, + IPP_TAG_DELETEATTR, + IPP_TAG_ADMINDEFINE, + IPP_TAG_INTEGER = 0x21, + IPP_TAG_BOOLEAN, + IPP_TAG_ENUM, + IPP_TAG_STRING = 0x30, + IPP_TAG_DATE, + IPP_TAG_RESOLUTION, + IPP_TAG_RANGE, + IPP_TAG_BEGIN_COLLECTION, + IPP_TAG_TEXTLANG, + IPP_TAG_NAMELANG, + IPP_TAG_END_COLLECTION, + IPP_TAG_TEXT = 0x41, + IPP_TAG_NAME, + IPP_TAG_KEYWORD = 0x44, + IPP_TAG_URI, + IPP_TAG_URISCHEME, + IPP_TAG_CHARSET, + IPP_TAG_LANGUAGE, + IPP_TAG_MIMETYPE, + IPP_TAG_MEMBERNAME, + IPP_TAG_MASK = 0x7fffffff, /* Mask for copied attribute values */ + IPP_TAG_COPY = 0x80000000 /* Bitflag for copied attribute values */ +} ipp_tag_t; + +typedef enum /**** Resolution units... ****/ +{ + IPP_RES_PER_INCH = 3, + IPP_RES_PER_CM +} ipp_res_t; + +typedef enum /**** Finishings... ****/ +{ + IPP_FINISHINGS_NONE = 3, + IPP_FINISHINGS_STAPLE, + IPP_FINISHINGS_PUNCH, + IPP_FINISHINGS_COVER, + IPP_FINISHINGS_BIND, + IPP_FINISHINGS_SADDLE_STITCH, + IPP_FINISHINGS_EDGE_STITCH, + IPP_FINISHINGS_FOLD, + IPP_FINISHINGS_TRIM, + IPP_FINISHINGS_BALE, + IPP_FINISHINGS_BOOKLET_MAKER, + IPP_FINISHINGS_JOB_OFFSET, + IPP_FINISHINGS_STAPLE_TOP_LEFT = 20, + IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, + IPP_FINISHINGS_STAPLE_TOP_RIGHT, + IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT, + IPP_FINISHINGS_EDGE_STITCH_LEFT, + IPP_FINISHINGS_EDGE_STITCH_TOP, + IPP_FINISHINGS_EDGE_STITCH_RIGHT, + IPP_FINISHINGS_EDGE_STITCH_BOTTOM, + IPP_FINISHINGS_STAPLE_DUAL_LEFT, + IPP_FINISHINGS_STAPLE_DUAL_TOP, + IPP_FINISHINGS_STAPLE_DUAL_RIGHT, + IPP_FINISHINGS_STAPLE_DUAL_BOTTOM, + IPP_FINISHINGS_BIND_LEFT = 50, + IPP_FINISHINGS_BIND_TOP, + IPP_FINISHINGS_BIND_RIGHT, + IPP_FINISHINGS_BIND_BOTTOM +} ipp_finish_t; + +typedef enum /**** Orientation... ****/ +{ + IPP_PORTRAIT = 3, /* No rotation */ + IPP_LANDSCAPE, /* 90 degrees counter-clockwise */ + IPP_REVERSE_LANDSCAPE, /* 90 degrees clockwise */ + IPP_REVERSE_PORTRAIT /* 180 degrees */ +} ipp_orient_t; + +typedef enum /**** Qualities... ****/ +{ + IPP_QUALITY_DRAFT = 3, + IPP_QUALITY_NORMAL, + IPP_QUALITY_HIGH +} ipp_quality_t; + +typedef enum /**** Job States.... */ +{ + IPP_JOB_PENDING = 3, + IPP_JOB_HELD, + IPP_JOB_PROCESSING, + IPP_JOB_STOPPED, + IPP_JOB_CANCELLED, + IPP_JOB_ABORTED, + IPP_JOB_COMPLETED +} ipp_jstate_t; + +typedef enum /**** Printer States.... */ +{ + IPP_PRINTER_IDLE = 3, + IPP_PRINTER_PROCESSING, + IPP_PRINTER_STOPPED +} ipp_pstate_t; + +typedef enum /**** IPP states... ****/ +{ + IPP_ERROR = -1, /* An error occurred */ + IPP_IDLE, /* Nothing is happening/request completed */ + IPP_HEADER, /* The request header needs to be sent/received */ + IPP_ATTRIBUTE, /* One or more attributes need to be sent/received */ + IPP_DATA /* IPP request data needs to be sent/received */ +} ipp_state_t; + +typedef enum /**** IPP operations... ****/ +{ + IPP_PRINT_JOB = 0x0002, + IPP_PRINT_URI, + IPP_VALIDATE_JOB, + IPP_CREATE_JOB, + IPP_SEND_DOCUMENT, + IPP_SEND_URI, + IPP_CANCEL_JOB, + IPP_GET_JOB_ATTRIBUTES, + IPP_GET_JOBS, + IPP_GET_PRINTER_ATTRIBUTES, + IPP_HOLD_JOB, + IPP_RELEASE_JOB, + IPP_RESTART_JOB, + IPP_PAUSE_PRINTER = 0x0010, + IPP_RESUME_PRINTER, + IPP_PURGE_JOBS, + IPP_SET_PRINTER_ATTRIBUTES, + IPP_SET_JOB_ATTRIBUTES, + IPP_GET_PRINTER_SUPPORTED_VALUES, + IPP_CREATE_PRINTER_SUBSCRIPTION, + IPP_CREATE_JOB_SUBSCRIPTION, + IPP_GET_SUBSCRIPTION_ATTRIBUTES, + IPP_GET_SUBSCRIPTIONS, + IPP_RENEW_SUBSCRIPTION, + IPP_CANCEL_SUBSCRIPTION, + IPP_GET_NOTIFICATIONS, + IPP_SEND_NOTIFICATIONS, + IPP_GET_PRINT_SUPPORT_FILES = 0x0021, + IPP_ENABLE_PRINTER, + IPP_DISABLE_PRINTER, + IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB, + IPP_HOLD_NEW_JOBS, + IPP_RELEASE_HELD_NEW_JOBS, + IPP_DEACTIVATE_PRINTER, + IPP_ACTIVATE_PRINTER, + IPP_RESTART_PRINTER, + IPP_SHUTDOWN_PRINTER, + IPP_STARTUP_PRINTER, + IPP_REPROCESS_JOB, + IPP_CANCEL_CURRENT_JOB, + IPP_SUSPEND_CURRENT_JOB, + IPP_RESUME_JOB, + IPP_PROMOTE_JOB, + IPP_SCHEDULE_JOB_AFTER, + IPP_PRIVATE = 0x4000, + CUPS_GET_DEFAULT, + CUPS_GET_PRINTERS, + CUPS_ADD_PRINTER, + CUPS_DELETE_PRINTER, + CUPS_GET_CLASSES, + CUPS_ADD_CLASS, + CUPS_DELETE_CLASS, + CUPS_ACCEPT_JOBS, + CUPS_REJECT_JOBS, + CUPS_SET_DEFAULT, + CUPS_GET_DEVICES, + CUPS_GET_PPDS, + CUPS_MOVE_JOB, + CUPS_ADD_DEVICE, + CUPS_DELETE_DEVICE +} ipp_op_t; + +typedef enum /**** IPP status codes... ****/ +{ + IPP_OK = 0x0000, + IPP_OK_SUBST, + IPP_OK_CONFLICT, + IPP_OK_IGNORED_SUBSCRIPTIONS, + IPP_OK_IGNORED_NOTIFICATIONS, + IPP_OK_TOO_MANY_EVENTS, + IPP_OK_BUT_CANCEL_SUBSCRIPTION, + IPP_REDIRECTION_OTHER_SITE = 0x300, + IPP_BAD_REQUEST = 0x0400, + IPP_FORBIDDEN, + IPP_NOT_AUTHENTICATED, + IPP_NOT_AUTHORIZED, + IPP_NOT_POSSIBLE, + IPP_TIMEOUT, + IPP_NOT_FOUND, + IPP_GONE, + IPP_REQUEST_ENTITY, + IPP_REQUEST_VALUE, + IPP_DOCUMENT_FORMAT, + IPP_ATTRIBUTES, + IPP_URI_SCHEME, + IPP_CHARSET, + IPP_CONFLICT, + IPP_COMPRESSION_NOT_SUPPORTED, + IPP_COMPRESSION_ERROR, + IPP_DOCUMENT_FORMAT_ERROR, + IPP_DOCUMENT_ACCESS_ERROR, + IPP_ATTRIBUTES_NOT_SETTABLE, + IPP_IGNORED_ALL_SUBSCRIPTIONS, + IPP_TOO_MANY_SUBSCRIPTIONS, + IPP_IGNORED_ALL_NOTIFICATIONS, + IPP_PRINT_SUPPORT_FILE_NOT_FOUND, + + IPP_INTERNAL_ERROR = 0x0500, + IPP_OPERATION_NOT_SUPPORTED, + IPP_SERVICE_UNAVAILABLE, + IPP_VERSION_NOT_SUPPORTED, + IPP_DEVICE_ERROR, + IPP_TEMPORARY_ERROR, + IPP_NOT_ACCEPTING, + IPP_PRINTER_BUSY, + IPP_ERROR_JOB_CANCELLED, + IPP_MULTIPLE_JOBS_NOT_SUPPORTED, + IPP_PRINTER_IS_DEACTIVATED +} ipp_status_t; + +typedef unsigned char ipp_uchar_t;/**** Unsigned 8-bit integer/character ****/ + +typedef union /**** Request Header ****/ +{ + struct /* Any Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + int op_status; /* Operation ID or status code*/ + int request_id; /* Request ID */ + } any; + + struct /* Operation Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + ipp_op_t operation_id; /* Operation ID */ + int request_id; /* Request ID */ + } op; + + struct /* Status Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + ipp_status_t status_code; /* Status code */ + int request_id; /* Request ID */ + } status; +} ipp_request_t; + + +typedef union /**** Attribute Value ****/ +{ + int integer; /* Integer/enumerated value */ + + char boolean; /* Boolean value */ + + ipp_uchar_t date[11]; /* Date/time value */ + + struct + { + int xres, /* Horizontal resolution */ + yres; /* Vertical resolution */ + ipp_res_t units; /* Resolution units */ + } resolution; /* Resolution value */ + + struct + { + int lower, /* Lower value */ + upper; /* Upper value */ + } range; /* Range of integers value */ + + struct + { + char *charset; /* Character set */ + char *text; /* String */ + } string; /* String with language value */ + + struct + { + int length; /* Length of attribute */ + void *data; /* Data in attribute */ + } unknown; /* Unknown attribute type */ +} ipp_value_t; + +typedef struct ipp_attribute_s /**** Attribute ****/ +{ + struct ipp_attribute_s *next; + /* Next atrtribute in list */ + ipp_tag_t group_tag, /* Job/Printer/Operation group tag */ + value_tag; /* What type of value is it? */ + char *name; /* Name of attribute */ + int num_values; /* Number of values */ + ipp_value_t values[1]; /* Values */ +} ipp_attribute_t; + +typedef struct /**** Request State ****/ +{ + ipp_state_t state; /* State of request */ + ipp_request_t request; /* Request header */ + ipp_attribute_t *attrs, /* Attributes */ + *last, /* Last attribute in list */ + *current; /* Current attribute (for read/write) */ + ipp_tag_t curtag; /* Current attribute group tag */ +} ipp_t; + + +/* + * Prototypes... + */ + +extern ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group, const char *name, char value); +extern ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const char *values); +extern ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group, const char *name, const ipp_uchar_t *value); +extern ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int value); +extern ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int num_values, const int *values); +extern ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group, const char *name, int lower, int upper); +extern ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const int *lower, const int *upper); +extern ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group, const char *name, ipp_res_t units, int xres, int yres); +extern ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, ipp_res_t units, const int *xres, const int *yres); +extern ipp_attribute_t *ippAddSeparator(ipp_t *ipp); +extern ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, const char *charset, const char *value); +extern ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int num_values, const char *charset, const char **values); +extern time_t ippDateToTime(const ipp_uchar_t *date); +extern void ippDelete(ipp_t *ipp); +extern const char *ippErrorString(ipp_status_t error); +extern ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t type); +extern size_t ippLength(ipp_t *ipp); +extern ipp_t *ippNew(void); +extern ipp_state_t ippRead(http_t *http, ipp_t *ipp); +extern const ipp_uchar_t *ippTimeToDate(time_t t); +extern ipp_state_t ippWrite(http_t *http, ipp_t *ipp); +extern int ippPort(void); +extern void ippSetPort(int p); + +extern ipp_attribute_t *_ipp_add_attr(ipp_t *, int); +extern void _ipp_free_attr(ipp_attribute_t *); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_IPP_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/language.c b/cups/language.c new file mode 100644 index 0000000000..0ac1b62a83 --- /dev/null +++ b/cups/language.c @@ -0,0 +1,407 @@ +/* + * "$Id$" + * + * I18N/language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) + * for the given language. + * cupsLangFlush() - Flush all language data out of the cache. + * cupsLangFree() - Free language data. + * cupsLangGet() - Get a language. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "string.h" +#include "language.h" + + +/* + * Local globals... + */ + +static cups_lang_t *lang_cache = NULL; /* Language string cache */ +static char *lang_blank = ""; /* Blank constant string */ +static char *lang_encodings[] = /* Encoding strings */ + { + "us-ascii", + "iso-8859-1", + "iso-8859-2", + "iso-8859-3", + "iso-8859-4", + "iso-8859-5", + "iso-8859-6", + "iso-8859-7", + "iso-8859-8", + "iso-8859-9", + "iso-8859-10", + "utf-8", + "iso-8859-13", + "iso-8859-14", + "iso-8859-15", + "windows-874", + "windows-1250", + "windows-1251", + "windows-1252", + "windows-1253", + "windows-1254", + "windows-1255", + "windows-1256", + "windows-1257", + "windows-1258" + }; +static char *lang_default[] = /* Default POSIX locale */ + { +#include "cups_C.h" + NULL + }; + + +/* + * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.) + * for the given language. + */ + +char * /* O - Character encoding */ +cupsLangEncoding(cups_lang_t *lang) /* I - Language data */ +{ + if (lang == NULL) + return (lang_encodings[0]); + else + return (lang_encodings[lang->encoding]); +} + + +/* + * 'cupsLangFlush()' - Flush all language data out of the cache. + */ + +void +cupsLangFlush(void) +{ + int i; /* Looping var */ + cups_lang_t *lang, /* Current language */ + *next; /* Next language */ + + + for (lang = lang_cache; lang != NULL; lang = next) + { + for (i = 0; i < CUPS_MSG_MAX; i ++) + if (lang->messages[i] != NULL && lang->messages[i] != lang_blank) + free(lang->messages[i]); + + next = lang->next; + free(lang); + } +} + + +/* + * 'cupsLangFree()' - Free language data. + * + * This does not actually free anything; use cupsLangFlush() for that. + */ + +void +cupsLangFree(cups_lang_t *lang) /* I - Language to free */ +{ + if (lang != NULL && lang->used > 0) + lang->used --; +} + + +/* + * 'cupsLangGet()' - Get a language. + */ + +cups_lang_t * /* O - Language data */ +cupsLangGet(const char *language) /* I - Language or locale */ +{ + int i, count; /* Looping vars */ + char langname[16], /* Requested language name */ + real[16], /* Real language name */ + filename[1024], /* Filename for language locale file */ + *localedir; /* Directory for locale files */ + FILE *fp; /* Language locale file pointer */ + char line[1024]; /* Line from file */ + cups_msg_t msg; /* Message number */ + char *text; /* Message text */ + cups_lang_t *lang; /* Current language... */ + + + /* + * Convert the language string passed in to a locale string. "C" is the + * standard POSIX locale and is copied unchanged. Otherwise the + * language string is converted from ll-cc (language-country) to ll_cc + * to match the file naming convention used by all POSIX-compliant + * operating systems. Any trailing character set specification is + * dropped. + */ + + if (language == NULL || language[0] == '\0' || + strcmp(language, "POSIX") == 0) + strcpy(langname, "C"); + else + { + /* + * Copy the locale string over safely... + */ + + strncpy(langname, language, sizeof(langname) - 1); + langname[sizeof(langname) - 1] = '\0'; + + /* + * Strip charset from "locale.charset"... + */ + + if ((text = strchr(langname, '.')) != NULL) + *text = '\0'; + } + + if (strlen(langname) < 2) + strcpy(real, "C"); + else + { + real[0] = tolower(langname[0]); + real[1] = tolower(langname[1]); + + if (langname[2] == '_' || langname[2] == '-') + { + real[2] = '_'; + real[3] = toupper(langname[3]); + real[4] = toupper(langname[4]); + real[5] = '\0'; + langname[5] = '\0'; + } + else + { + langname[2] = '\0'; + real[2] = '\0'; + } + } + + /* + * Next try to open a locale file; we will try the country-localized file + * first, and then look for generic language file. If all else fails we + * will use the POSIX locale. + */ + + if ((localedir = getenv("LOCALEDIR")) == NULL) + localedir = CUPS_LOCALEDIR; + + snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir, real, real); + + if ((fp = fopen(filename, "r")) == NULL) + if (strlen(real) > 2) + { + /* + * Nope, see if we can open a generic language file... + */ + + real[2] = '\0'; + snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir, real, + real); + fp = fopen(filename, "r"); + } + + /* + * Then see if we already have this language loaded... + */ + + for (lang = lang_cache; lang != NULL; lang = lang->next) + if (strcmp(lang->language, langname) == 0) + { + lang->used ++; + + if (fp != NULL) + fclose(fp); + + return (lang); + } + + /* + * OK, we have an open messages file; the first line will contain the + * language encoding (us-ascii, iso-8859-1, etc.), and the rest will + * be messages consisting of: + * + * #### SP message text + * + * or: + * + * message text + * + * If the line starts with a number, then message processing picks up + * where the number indicates. Otherwise the last message number is + * incremented. + * + * All leading whitespace is deleted. + */ + + if (fp == NULL) + { + strncpy(line, lang_default[0], sizeof(line) - 1); + line[sizeof(line) - 1] = '\0'; + } + else if (fgets(line, sizeof(line), fp) == NULL) + { + /* + * Can't read encoding! + */ + + fclose(fp); + return (NULL); + } + + i = strlen(line) - 1; + if (line[i] == '\n') + line[i] = '\0'; /* Strip LF */ + + /* + * See if there is a free language available; if so, use that + * record... + */ + + for (lang = lang_cache; lang != NULL; lang = lang->next) + if (lang->used == 0) + break; + + if (lang == NULL) + { + /* + * Allocate memory for the language and add it to the cache. + */ + + if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL) + { + fclose(fp); + return (NULL); + } + + lang->next = lang_cache; + lang_cache = lang; + } + + /* + * Free all old strings as needed... + */ + + for (i = 0; i < CUPS_MSG_MAX; i ++) + { + if (lang->messages[i] != NULL && lang->messages[i] != lang_blank) + free(lang->messages[i]); + + lang->messages[i] = lang_blank; + } + + /* + * Then assign the language and encoding fields... + */ + + lang->used ++; + strncpy(lang->language, langname, sizeof(lang->language) - 1); + lang->language[sizeof(lang->language) - 1] = '\0'; + + for (i = 0; i < (sizeof(lang_encodings) / sizeof(lang_encodings[0])); i ++) + if (strcmp(lang_encodings[i], line) == 0) + { + lang->encoding = (cups_encoding_t)i; + break; + } + + /* + * Read the strings from the file... + */ + + msg = (cups_msg_t)-1; + count = 1; + + for (;;) + { + /* + * Read a line from memory or from a file... + */ + + if (fp == NULL) + { + if (lang_default[count] == NULL) + break; + + strncpy(line, lang_default[count], sizeof(line) - 1); + /* Already set last byte to 0 above... */ + } + else if (fgets(line, sizeof(line), fp) == NULL) + break; + + count ++; + + /* + * Ignore blank lines... + */ + + i = strlen(line) - 1; + if (line[i] == '\n') + line[i] = '\0'; /* Strip LF */ + + if (line[0] == '\0') + continue; + + /* + * Grab the message number and text... + */ + + if (isdigit(line[0])) + msg = (cups_msg_t)atoi(line); + else + msg ++; + + if (msg < 0 || msg >= CUPS_MSG_MAX) + continue; + + text = line; + while (isdigit(*text)) + text ++; + while (isspace(*text)) + text ++; + + lang->messages[msg] = strdup(text); + } + + /* + * Close the file and return... + */ + + if (fp != NULL) + fclose(fp); + + return (lang); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/language.h b/cups/language.h new file mode 100644 index 0000000000..5da511389e --- /dev/null +++ b/cups/language.h @@ -0,0 +1,222 @@ +/* + * "$Id$" + * + * Multi-language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_LANGUAGE_H_ +# define _CUPS_LANGUAGE_H_ + +/* + * Include necessary headers... + */ + +# include + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * Messages... + */ + +typedef enum /**** Message Indices ****/ +{ + CUPS_MSG_OK, + CUPS_MSG_CANCEL, + CUPS_MSG_HELP, + CUPS_MSG_QUIT, + CUPS_MSG_CLOSE, + CUPS_MSG_YES, + CUPS_MSG_NO, + CUPS_MSG_ON, + CUPS_MSG_OFF, + CUPS_MSG_SAVE, + CUPS_MSG_DISCARD, + CUPS_MSG_DEFAULT, + CUPS_MSG_OPTIONS, + CUPS_MSG_MORE_INFO, + CUPS_MSG_BLACK, + CUPS_MSG_COLOR, + CUPS_MSG_CYAN, + CUPS_MSG_MAGENTA, + CUPS_MSG_YELLOW, + CUPS_MSG_COPYRIGHT, + CUPS_MSG_GENERAL, + CUPS_MSG_PRINTER, + CUPS_MSG_IMAGE, + CUPS_MSG_HPGL2, + CUPS_MSG_EXTRA, + CUPS_MSG_DOCUMENT, + CUPS_MSG_OTHER, + CUPS_MSG_PRINT_PAGES, + CUPS_MSG_ENTIRE_DOCUMENT, + CUPS_MSG_PAGE_RANGE, + CUPS_MSG_REVERSE_ORDER, + CUPS_MSG_PAGE_FORMAT, + CUPS_MSG_1_UP, + CUPS_MSG_2_UP, + CUPS_MSG_4_UP, + CUPS_MSG_IMAGE_SCALING, + CUPS_MSG_USE_NATURAL_IMAGE_SIZE, + CUPS_MSG_ZOOM_BY_PERCENT, + CUPS_MSG_ZOOM_BY_PPI, + CUPS_MSG_MIRROR_IMAGE, + CUPS_MSG_COLOR_SATURATION, + CUPS_MSG_COLOR_HUE, + CUPS_MSG_FIT_TO_PAGE, + CUPS_MSG_SHADING, + CUPS_MSG_DEFAULT_PEN_WIDTH, + CUPS_MSG_GAMMA_CORRECTION, + CUPS_MSG_BRIGHTNESS, + CUPS_MSG_ADD, + CUPS_MSG_DELETE, + CUPS_MSG_MODIFY, + CUPS_MSG_PRINTER_URI, + CUPS_MSG_PRINTER_NAME, + CUPS_MSG_PRINTER_LOCATION, + CUPS_MSG_PRINTER_INFO, + CUPS_MSG_PRINTER_MAKE_AND_MODEL, + CUPS_MSG_DEVICE_URI, + CUPS_MSG_FORMATTING_PAGE, + CUPS_MSG_PRINTING_PAGE, + CUPS_MSG_INITIALIZING_PRINTER, + CUPS_MSG_PRINTER_STATE, + CUPS_MSG_ACCEPTING_JOBS, + CUPS_MSG_NOT_ACCEPTING_JOBS, + CUPS_MSG_PRINT_JOBS, + CUPS_MSG_CLASS, + CUPS_MSG_LOCAL, + CUPS_MSG_REMOTE, + CUPS_MSG_DUPLEXING, + CUPS_MSG_STAPLING, + CUPS_MSG_FAST_COPIES, + CUPS_MSG_COLLATED_COPIES, + CUPS_MSG_PUNCHING, + CUPS_MSG_COVERING, + CUPS_MSG_BINDING, + CUPS_MSG_SORTING, + CUPS_MSG_SMALL, + CUPS_MSG_MEDIUM, + CUPS_MSG_LARGE, + CUPS_MSG_VARIABLE, + CUPS_MSG_IDLE, + CUPS_MSG_PROCESSING, + CUPS_MSG_STOPPED, + CUPS_MSG_ALL, + CUPS_MSG_ODD, + CUPS_MSG_EVEN_PAGES, + CUPS_MSG_DARKER_LIGHTER, + CUPS_MSG_MEDIA_SIZE, + CUPS_MSG_MEDIA_TYPE, + CUPS_MSG_MEDIA_SOURCE, + CUPS_MSG_ORIENTATION, + CUPS_MSG_PORTRAIT, + CUPS_MSG_LANDSCAPE, + CUPS_MSG_JOB_STATE, + CUPS_MSG_JOB_NAME, + CUPS_MSG_USER_NAME, + CUPS_MSG_PRIORITY, + CUPS_MSG_COPIES, + CUPS_MSG_FILE_SIZE, + CUPS_MSG_PENDING, + CUPS_MSG_OUTPUT_MODE, + CUPS_MSG_RESOLUTION, + CUPS_MSG_TEXT, + CUPS_MSG_PRETTYPRINT, + CUPS_MSG_MARGINS, + CUPS_MSG_LEFT, + CUPS_MSG_RIGHT, + CUPS_MSG_BOTTOM, + CUPS_MSG_TOP, + CUPS_MSG_FILENAME, + CUPS_MSG_PRINT, + CUPS_MSG_HTTP_BASE = 200, + CUPS_MSG_HTTP_END = 505, + CUPS_MSG_MAX +} cups_msg_t; + +typedef enum /**** Language Encodings ****/ +{ + CUPS_US_ASCII, + CUPS_ISO8859_1, + CUPS_ISO8859_2, + CUPS_ISO8859_3, + CUPS_ISO8859_4, + CUPS_ISO8859_5, + CUPS_ISO8859_6, + CUPS_ISO8859_7, + CUPS_ISO8859_8, + CUPS_ISO8859_9, + CUPS_ISO8859_10, + CUPS_UTF8, + CUPS_ISO8859_13, + CUPS_ISO8859_14, + CUPS_ISO8859_15, + CUPS_WINDOWS_874, + CUPS_WINDOWS_1250, + CUPS_WINDOWS_1251, + CUPS_WINDOWS_1252, + CUPS_WINDOWS_1253, + CUPS_WINDOWS_1254, + CUPS_WINDOWS_1255, + CUPS_WINDOWS_1256, + CUPS_WINDOWS_1257, + CUPS_WINDOWS_1258 +} cups_encoding_t; + +typedef struct cups_lang_str /**** Language Cache Structure ****/ +{ + struct cups_lang_str *next; /* Next language in cache */ + int used; /* Number of times this entry has been used. */ + cups_encoding_t encoding; /* Text encoding */ + char language[16]; /* Language/locale name */ + char *messages[CUPS_MSG_MAX]; + /* Message array */ +} cups_lang_t; + + +/* + * Prototypes... + */ + +# ifdef WIN32 +# define cupsLangDefault() cupsLangGet(setlocale(LC_ALL, "")) +# else /* This fix works around bugs in the Linux and HP-UX setlocale() */ +# define cupsLangDefault() cupsLangGet(getenv("LANG")) +# endif /* WIN32 */ + +extern char *cupsLangEncoding(cups_lang_t *lang); +extern void cupsLangFlush(void); +extern void cupsLangFree(cups_lang_t *lang); +extern cups_lang_t *cupsLangGet(const char *language); +# define cupsLangString(lang,msg) (lang)->messages[(msg)] + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_LANGUAGE_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/mark.c b/cups/mark.c new file mode 100644 index 0000000000..d281cd3859 --- /dev/null +++ b/cups/mark.c @@ -0,0 +1,441 @@ +/* + * "$Id$" + * + * Option marking routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdConflicts() - Check to see if there are any conflicts. + * ppdFindChoice() - Return a pointer to an option choice. + * ppdFindMarkedChoice() - Return the marked choice for the specified option. + * ppdFindOption() - Return a pointer to the specified option. + * ppdIsMarked() - Check to see if an option is marked... + * ppdMarkDefaults() - Mark all default options in the PPD file. + * ppdMarkOption() - Mark an option in a PPD file. + * ppd_defaults() - Set the defaults for this group and all sub-groups. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" +#include "debug.h" + + +/* + * Local functions... + */ + +static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g); + + +/* + * 'ppdConflicts()' - Check to see if there are any conflicts. + */ + +int /* O - Number of conflicts found */ +ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */ +{ + int i, j, k, /* Looping variables */ + conflicts; /* Number of conflicts */ + ppd_const_t *c; /* Current constraint */ + ppd_group_t *g, *sg; /* Groups */ + ppd_option_t *o1, *o2; /* Options */ + ppd_choice_t *c1, *c2; /* Choices */ + + + if (ppd == NULL) + return (0); + + /* + * Clear all conflicts... + */ + + conflicts = 0; + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o1 = g->options; j > 0; j --, o1 ++) + o1->conflicted = 0; + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o1 = sg->options; k > 0; k --, o1 ++) + o1->conflicted = 0; + } + + /* + * Loop through all of the UI constraints and flag any options + * that conflict... + */ + + for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) + { + /* + * Grab pointers to the first option... + */ + + o1 = ppdFindOption(ppd, c->option1); + + if (o1 == NULL) + continue; + else if (c->choice1[0] != '\0') + { + /* + * This constraint maps to a specific choice. + */ + + c1 = ppdFindChoice(o1, c->choice1); + } + else + { + /* + * This constraint applies to any choice for this option. + */ + + for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++) + if (c1->marked) + break; + + if (j == 0 || + strcasecmp(c1->choice, "None") == 0 || + strcasecmp(c1->choice, "Off") == 0 || + strcasecmp(c1->choice, "False") == 0) + c1 = NULL; + } + + /* + * Grab pointers to the second option... + */ + + o2 = ppdFindOption(ppd, c->option2); + + if (o2 == NULL) + continue; + else if (c->choice2[0] != '\0') + { + /* + * This constraint maps to a specific choice. + */ + + c2 = ppdFindChoice(o2, c->choice2); + } + else + { + /* + * This constraint applies to any choice for this option. + */ + + for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++) + if (c2->marked) + break; + + if (j == 0 || + strcasecmp(c2->choice, "None") == 0 || + strcasecmp(c2->choice, "Off") == 0 || + strcasecmp(c2->choice, "False") == 0) + c2 = NULL; + } + + /* + * If both options are marked then there is a conflict... + */ + + if (c1 != NULL && c1->marked && + c2 != NULL && c2->marked) + { + DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n", + o1->keyword, c1->choice, o2->keyword, c2->choice, + c->option1, c->choice1, c->option2, c->choice2)); + conflicts ++; + o1->conflicted = 1; + o2->conflicted = 1; + } + } + + /* + * Return the number of conflicts found... + */ + + return (conflicts); +} + + +/* + * 'ppdFindChoice()' - Return a pointer to an option choice. + */ + +ppd_choice_t * /* O - Choice pointer or NULL */ +ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */ + const char *choice) /* I - Name of choice */ +{ + int i; /* Looping var */ + ppd_choice_t *c; /* Current choice */ + + + if (o == NULL || choice == NULL) + return (NULL); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcasecmp(c->choice, choice) == 0) + return (c); + + return (NULL); +} + + +/* + * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option. + */ + +ppd_choice_t * /* O - Pointer to choice or NULL */ +ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */ + const char *option) /* I - Keyword/option name */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Pointer to option */ + ppd_choice_t *c; /* Pointer to choice */ + + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (NULL); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (c->marked) + return (c); + + return (NULL); +} + + +/* + * 'ppdFindOption()' - Return a pointer to the specified option. + */ + +ppd_option_t * /* O - Pointer to option or NULL */ +ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */ + const char *option) /* I - Option/Keyword name */ +{ + int i, j, k; /* Looping vars */ + ppd_option_t *o; /* Pointer to option */ + ppd_group_t *g, /* Pointer to group */ + *sg; /* Pointer to subgroup */ + + + if (ppd == NULL || option == NULL) + return (NULL); + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o = g->options; j > 0; j --, o ++) + if (strcasecmp(o->keyword, option) == 0) + return (o); + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o = sg->options; k > 0; k --, o ++) + if (strcasecmp(o->keyword, option) == 0) + return (o); + } + + return (NULL); +} + + +/* + * 'ppdIsMarked()' - Check to see if an option is marked... + */ + +int /* O - Non-zero if option is marked */ +ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */ + const char *option, /* I - Option/Keyword name */ + const char *choice) /* I - Choice name */ +{ + ppd_option_t *o; /* Option pointer */ + ppd_choice_t *c; /* Choice pointer */ + + + if (ppd == NULL) + return (0); + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (0); + + if ((c = ppdFindChoice(o, choice)) == NULL) + return (0); + + return (c->marked); +} + + +/* + * 'ppdMarkDefaults()' - Mark all default options in the PPD file. + */ + +void +ppdMarkDefaults(ppd_file_t *ppd)/* I - PPD file record */ +{ + int i; /* Looping variables */ + ppd_group_t *g; /* Current group */ + + + if (ppd == NULL) + return; + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + ppd_defaults(ppd, g); +} + + +/* + * 'ppdMarkOption()' - Mark an option in a PPD file. + * + * Notes: + * + * -1 is returned if the given option would conflict with any currently + * selected option. + */ + +int /* O - Number of conflicts */ +ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */ + const char *option, /* I - Keyword */ + const char *choice) /* I - Option name */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Option pointer */ + ppd_choice_t *c; /* Choice pointer */ + + + if (ppd == NULL) + return (0); + + if (strcasecmp(option, "PageSize") == 0 && strncasecmp(choice, "Custom.", 7) == 0) + { + /* + * Handle variable page sizes... + */ + + ppdPageSize(ppd, choice); + choice = "Custom"; + } + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (0); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcasecmp(c->choice, choice) == 0) + break; + + if (i) + { + /* + * Option found; mark it and then handle unmarking any other options. + */ + + c->marked = 1; + + if (o->ui != PPD_UI_PICKMANY) + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcasecmp(c->choice, choice) != 0) + c->marked = 0; + + if (strcasecmp(option, "PageSize") == 0 || strcasecmp(option, "PageRegion") == 0) + { + /* + * Mark current page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + ppd->sizes[i].marked = strcasecmp(ppd->sizes[i].name, choice) == 0; + + /* + * Unmark the current PageSize or PageRegion setting, as appropriate... + */ + + if (strcasecmp(option, "PageSize") == 0) + { + if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + else + { + if ((o = ppdFindOption(ppd, "PageSize")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + } + else if (strcasecmp(option, "InputSlot") == 0) + { + /* + * Unmark ManualFeed option... + */ + + if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + else if (strcasecmp(option, "ManualFeed") == 0) + { + /* + * Unmark InputSlot option... + */ + + if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + } + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppd_defaults()' - Set the defaults for this group and all sub-groups. + */ + +static void +ppd_defaults(ppd_file_t *ppd, /* I - PPD file */ + ppd_group_t *g) /* I - Group to default */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Current option */ + ppd_group_t *sg; /* Current sub-group */ + + + if (g == NULL) + return; + + for (i = g->num_options, o = g->options; i > 0; i --, o ++) + if (strcasecmp(o->keyword, "PageRegion") != 0) + ppdMarkOption(ppd, o->keyword, o->defchoice); + + for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++) + ppd_defaults(ppd, sg); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/md5.c b/cups/md5.c new file mode 100644 index 0000000000..5db868858e --- /dev/null +++ b/cups/md5.c @@ -0,0 +1,392 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/*$Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include "string.h" + +#ifdef TEST +/* + * Compile with -DTEST to create a self-contained executable test program. + * The test program should print out the same values as given in section + * A.5 of RFC 1321, reproduced below. + */ +main() +{ + static const char *const test[7] = { + "", /*d41d8cd98f00b204e9800998ecf8427e*/ + "a", /*0cc175b9c0f1b6a831c399e269772661*/ + "abc", /*900150983cd24fb0d6963f7d28e17f72*/ + "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ + "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + /*d174ab98d277d9f5a5611c2c9f419d9f*/ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ + }; + int i; + + for (i = 0; i < 7; ++i) { + md5_state_t state; + md5_byte_t digest[16]; + int di; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); + md5_finish(&state, digest); + printf("MD5 (\"%s\") = ", test[i]); + for (di = 0; di < 16; ++di) + printf("%02x", digest[di]); + printf("\n"); + } + return 0; +} +#endif /* TEST */ + + +/* + * For reference, here is the program that computed the T values. + */ +#if 0 +#include +main() +{ + int i; + for (i = 1; i <= 64; ++i) { + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + printf("#define T%d 0x%08lx\n", i, v); + } + return 0; +} +#endif +/* + * End of T computation program. + */ +#define T1 0xd76aa478 +#define T2 0xe8c7b756 +#define T3 0x242070db +#define T4 0xc1bdceee +#define T5 0xf57c0faf +#define T6 0x4787c62a +#define T7 0xa8304613 +#define T8 0xfd469501 +#define T9 0x698098d8 +#define T10 0x8b44f7af +#define T11 0xffff5bb1 +#define T12 0x895cd7be +#define T13 0x6b901122 +#define T14 0xfd987193 +#define T15 0xa679438e +#define T16 0x49b40821 +#define T17 0xf61e2562 +#define T18 0xc040b340 +#define T19 0x265e5a51 +#define T20 0xe9b6c7aa +#define T21 0xd62f105d +#define T22 0x02441453 +#define T23 0xd8a1e681 +#define T24 0xe7d3fbc8 +#define T25 0x21e1cde6 +#define T26 0xc33707d6 +#define T27 0xf4d50d87 +#define T28 0x455a14ed +#define T29 0xa9e3e905 +#define T30 0xfcefa3f8 +#define T31 0x676f02d9 +#define T32 0x8d2a4c8a +#define T33 0xfffa3942 +#define T34 0x8771f681 +#define T35 0x6d9d6122 +#define T36 0xfde5380c +#define T37 0xa4beea44 +#define T38 0x4bdecfa9 +#define T39 0xf6bb4b60 +#define T40 0xbebfbc70 +#define T41 0x289b7ec6 +#define T42 0xeaa127fa +#define T43 0xd4ef3085 +#define T44 0x04881d05 +#define T45 0xd9d4d039 +#define T46 0xe6db99e5 +#define T47 0x1fa27cf8 +#define T48 0xc4ac5665 +#define T49 0xf4292244 +#define T50 0x432aff97 +#define T51 0xab9423a7 +#define T52 0xfc93a039 +#define T53 0x655b59c3 +#define T54 0x8f0ccc92 +#define T55 0xffeff47d +#define T56 0x85845dd1 +#define T57 0x6fa87e4f +#define T58 0xfe2ce6e0 +#define T59 0xa3014314 +#define T60 0x4e0811a1 +#define T61 0xf7537e82 +#define T62 0xbd3af235 +#define T63 0x2ad7d2bb +#define T64 0xeb86d391 + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + +#ifndef ARCH_IS_BIG_ENDIAN +# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ +#endif +#if ARCH_IS_BIG_ENDIAN + + /* + * On big-endian machines, we must arrange the bytes in the right + * order. (This also works on machines of unknown byte order.) + */ + md5_word_t X[16]; + const md5_byte_t *xp = data; + int i; + + for (i = 0; i < 16; ++i, xp += 4) + X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + +#else /* !ARCH_IS_BIG_ENDIAN */ + + /* + * On little-endian machines, we can process properly aligned data + * without copying it. + */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } +#endif + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = 0xefcdab89; + pms->abcd[2] = 0x98badcfe; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/cups/md5.h b/cups/md5.h new file mode 100644 index 0000000000..a2d7b34156 --- /dev/null +++ b/cups/md5.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/*$Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This code has some adaptations for the Ghostscript environment, but it + * will compile and run correctly in any environment with 8-bit chars and + * 32-bit ints. Specifically, it assumes that if the following are + * defined, they have the same meaning as in Ghostscript: P1, P2, P3, + * ARCH_IS_BIG_ENDIAN. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +#ifdef P1 +void md5_init(P1(md5_state_t *pms)); +#else +void md5_init(md5_state_t *pms); +#endif + +/* Append a string to the message. */ +#ifdef P3 +void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes)); +#else +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); +#endif + +/* Finish the message and return the digest. */ +#ifdef P2 +void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16])); +#else +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); +#endif + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/cups/md5passwd.c b/cups/md5passwd.c new file mode 100644 index 0000000000..1b2725e056 --- /dev/null +++ b/cups/md5passwd.c @@ -0,0 +1,148 @@ +/* + * "$Id$" + * + * MD5 password support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * httpMD5() - Compute the MD5 sum of the username:group:password. + * httpMD5Nonce() - Combine the MD5 sum of the username, group, and password + * with the server-supplied nonce value. + * httpMD5String() - Convert an MD5 sum to a character string. + */ + +/* + * Include necessary headers... + */ + +#include "http.h" +#include "string.h" + + +/* + * 'httpMD5()' - Compute the MD5 sum of the username:group:password. + */ + +char * /* O - MD5 sum */ +httpMD5(const char *username, /* I - User name */ + const char *realm, /* I - Realm name */ + const char *passwd, /* I - Password string */ + char md5[33]) /* O - MD5 string */ +{ + md5_state_t state; /* MD5 state info */ + md5_byte_t sum[16]; /* Sum data */ + char line[256]; /* Line to sum */ + + + /* + * Compute the MD5 sum of the user name, group name, and password. + */ + + snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd); + md5_init(&state); + md5_append(&state, (md5_byte_t *)line, strlen(line)); + md5_finish(&state, sum); + + /* + * Return the sum... + */ + + return (httpMD5String(sum, md5)); +} + + +/* + * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password + * with the server-supplied nonce value, method, and + * request-uri. + */ + +char * /* O - New sum */ +httpMD5Final(const char *nonce, /* I - Server nonce value */ + const char *method, /* I - METHOD (GET, POST, etc.) */ + const char *resource, /* I - Resource path */ + char md5[33]) /* IO - MD5 sum */ +{ + md5_state_t state; /* MD5 state info */ + md5_byte_t sum[16]; /* Sum data */ + char line[1024]; /* Line of data */ + char a2[33]; /* Hash of method and resource */ + + + /* + * First compute the MD5 sum of the method and resource... + */ + + snprintf(line, sizeof(line), "%s:%s", method, resource); + md5_init(&state); + md5_append(&state, (md5_byte_t *)line, strlen(line)); + md5_finish(&state, sum); + httpMD5String(sum, a2); + + /* + * Then combine A1 (MD5 of username, realm, and password) with the nonce + * and A2 (method + resource) values to get the final MD5 sum for the + * request... + */ + + snprintf(line, sizeof(line), "%s%s:%s", md5, nonce, a2); + + md5_init(&state); + md5_append(&state, (md5_byte_t *)line, strlen(line)); + md5_finish(&state, sum); + + return (httpMD5String(sum, md5)); +} + + +/* + * 'httpMD5String()' - Convert an MD5 sum to a character string. + */ + +char * /* O - MD5 sum in hex */ +httpMD5String(const md5_byte_t *sum, /* I - MD5 sum data */ + char md5[33]) /* O - MD5 sum in hex */ +{ + int i; /* Looping var */ + char *md5ptr; /* Pointer into MD5 string */ + static char *hex = "0123456789abcdef"; + /* Hex digits */ + + + /* + * Convert the MD5 sum to hexadecimal... + */ + + for (i = 16, md5ptr = md5; i > 0; i --, sum ++) + { + *md5ptr++ = hex[*sum >> 4]; + *md5ptr++ = hex[*sum & 15]; + } + + *md5ptr = '\0'; + + return (md5); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/options.c b/cups/options.c new file mode 100644 index 0000000000..6482ac31a8 --- /dev/null +++ b/cups/options.c @@ -0,0 +1,420 @@ +/* + * "$Id$" + * + * Option routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsAddOption() - Add an option to an option array. + * cupsFreeOptions() - Free all memory used by options. + * cupsGetOption() - Get an option value. + * cupsParseOptions() - Parse options from a command-line argument. + * cupsMarkOptions() - Mark command-line options in a PPD file. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include "string.h" +#include "debug.h" + + +/* + * 'cupsAddOption()' - Add an option to an option array. + */ + +int /* O - Number of options */ +cupsAddOption(const char *name, /* I - Name of option */ + const char *value, /* I - Value of option */ + int num_options, /* I - Number of options */ + cups_option_t **options) /* IO - Pointer to options */ +{ + int i; /* Looping var */ + cups_option_t *temp; /* Pointer to new option */ + + + if (name == NULL || !name[0] || value == NULL || + options == NULL || num_options < 0) + return (num_options); + + /* + * Look for an existing option with the same name... + */ + + for (i = 0, temp = *options; i < num_options; i ++, temp ++) + if (strcasecmp(temp->name, name) == 0) + break; + + if (i >= num_options) + { + /* + * No matching option name... + */ + + if (num_options == 0) + temp = (cups_option_t *)malloc(sizeof(cups_option_t)); + else + temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * + (num_options + 1)); + + if (temp == NULL) + return (0); + + *options = temp; + temp += num_options; + temp->name = strdup(name); + num_options ++; + } + else + { + /* + * Match found; free the old value... + */ + + free(temp->value); + } + + temp->value = strdup(value); + + return (num_options); +} + + +/* + * 'cupsFreeOptions()' - Free all memory used by options. + */ + +void +cupsFreeOptions(int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Pointer to options */ +{ + int i; /* Looping var */ + + + if (num_options <= 0 || options == NULL) + return; + + for (i = 0; i < num_options; i ++) + { + free(options[i].name); + free(options[i].value); + } + + free(options); +} + + +/* + * 'cupsGetOption()' - Get an option value. + */ + +const char * /* O - Option value or NULL */ +cupsGetOption(const char *name, /* I - Name of option */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + + + if (name == NULL || num_options <= 0 || options == NULL) + return (NULL); + + for (i = 0; i < num_options; i ++) + if (strcasecmp(options[i].name, name) == 0) + return (options[i].value); + + return (NULL); +} + + +/* + * 'cupsParseOptions()' - Parse options from a command-line argument. + */ + +int /* O - Number of options found */ +cupsParseOptions(const char *arg, /* I - Argument to parse */ + int num_options, /* I - Number of options */ + cups_option_t **options) /* O - Options found */ +{ + char *copyarg, /* Copy of input string */ + *ptr, /* Pointer into string */ + *name, /* Pointer to name */ + *value; /* Pointer to value */ + + + if (arg == NULL || options == NULL || num_options < 0) + return (0); + + /* + * Make a copy of the argument string and then divide it up... + */ + + copyarg = strdup(arg); + ptr = copyarg; + + /* + * Skip leading spaces... + */ + + while (isspace(*ptr)) + ptr ++; + + /* + * Loop through the string... + */ + + while (*ptr != '\0') + { + /* + * Get the name up to a SPACE, =, or end-of-string... + */ + + name = ptr; + while (!isspace(*ptr) && *ptr != '=' && *ptr != '\0') + ptr ++; + + /* + * Avoid an empty name... + */ + + if (ptr == name) + break; + + /* + * Skip trailing spaces... + */ + + while (isspace(*ptr)) + *ptr++ = '\0'; + + if (*ptr != '=') + { + /* + * Start of another option... + */ + + if (strncasecmp(name, "no", 2) == 0) + num_options = cupsAddOption(name + 2, "false", num_options, + options); + else + num_options = cupsAddOption(name, "true", num_options, options); + + continue; + } + + /* + * Remove = and parse the value... + */ + + *ptr++ = '\0'; + + if (*ptr == '\'') + { + /* + * Quoted string constant... + */ + + ptr ++; + value = ptr; + + while (*ptr != '\'' && *ptr != '\0') + ptr ++; + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else if (*ptr == '\"') + { + /* + * Double-quoted string constant... + */ + + ptr ++; + value = ptr; + + while (*ptr != '\"' && *ptr != '\0') + ptr ++; + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else + { + /* + * Normal space-delimited string... + */ + + value = ptr; + + while (!isspace(*ptr) && *ptr != '\0') + ptr ++; + + while (isspace(*ptr)) + *ptr++ = '\0'; + } + + /* + * Add the string value... + */ + + num_options = cupsAddOption(name, value, num_options, options); + } + + /* + * Free the copy of the argument we made and return the number of options + * found. + */ + + free(copyarg); + + return (num_options); +} + + +/* + * 'cupsMarkOptions()' - Mark command-line options in a PPD file. + */ + +int /* O - 1 if conflicting */ +cupsMarkOptions(ppd_file_t *ppd, /* I - PPD file */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + int conflict; /* Option conflicts */ + char *val, /* Pointer into value */ + *ptr, /* Pointer into string */ + s[255]; /* Temporary string */ + + + /* + * Check arguments... + */ + + if (ppd == NULL || num_options <= 0 || options == NULL) + return (0); + + /* + * Mark options... + */ + + conflict = 0; + + for (i = num_options; i > 0; i --, options ++) + if (strcasecmp(options->name, "media") == 0) + { + /* + * Loop through the option string, separating it at commas and + * marking each individual option. + */ + + for (val = options->value; *val;) + { + /* + * Extract the sub-option from the string... + */ + + for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) + *ptr++ = *val++; + *ptr++ = '\0'; + + if (*val == ',') + val ++; + + /* + * Mark it... + */ + + if (ppdMarkOption(ppd, "PageSize", s)) + conflict = 1; + if (ppdMarkOption(ppd, "InputSlot", s)) + conflict = 1; + if (ppdMarkOption(ppd, "MediaType", s)) + conflict = 1; + if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ + conflict = 1; + if (strcasecmp(s, "manual") == 0) + if (ppdMarkOption(ppd, "ManualFeed", "True")) + conflict = 1; + } + } + else if (strcasecmp(options->name, "sides") == 0) + { + if (strcasecmp(options->value, "one-sided") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "None")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "None")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "None")) /* Kodak */ + conflict = 1; + } + else if (strcasecmp(options->value, "two-sided-long-edge") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "DuplexNoTumble")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "DuplexNoTumble")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "DuplexNoTumble")) /* Kodak */ + conflict = 1; + } + else if (strcasecmp(options->value, "two-sided-short-edge") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "DuplexTumble")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "DuplexTumble")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "DuplexTumble")) /* Kodak */ + conflict = 1; + } + } + else if (strcasecmp(options->name, "resolution") == 0 || + strcasecmp(options->name, "printer-resolution") == 0) + { + if (ppdMarkOption(ppd, "Resolution", options->value)) + conflict = 1; + if (ppdMarkOption(ppd, "SetResolution", options->value)) + /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ + conflict = 1; + if (ppdMarkOption(ppd, "JCLResolution", options->value)) /* HP */ + conflict = 1; + if (ppdMarkOption(ppd, "CNRes_PGP", options->value)) /* Canon */ + conflict = 1; + } + else if (strcasecmp(options->name, "output-bin") == 0) + { + if (ppdMarkOption(ppd, "OutputBin", options->value)) + conflict = 1; + } + else if (ppdMarkOption(ppd, options->name, options->value)) + conflict = 1; + + return (conflict); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/page.c b/cups/page.c new file mode 100644 index 0000000000..63d85ba83a --- /dev/null +++ b/cups/page.c @@ -0,0 +1,189 @@ +/* + * "$Id$" + * + * Page size functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdPageSize() - Get the page size record for the given size. + * ppdPageWidth() - Get the page width for the given size. + * ppdPageLength() - Get the page length for the given size. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" +#include + + +/* + * 'ppdPageSize()' - Get the page size record for the given size. + */ + +ppd_size_t * /* O - Size record for page or NULL */ +ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + int i; /* Looping var */ + float w, l; /* Width and length of page */ + char units[255]; /* Page size units... */ + + + if (ppd == NULL) + return (NULL); + + if (name != NULL) + { + if (strncmp(name, "Custom.", 7) == 0 && ppd->variable_sizes) + { + /* + * Find the custom page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp("Custom", ppd->sizes[i].name) == 0) + break; + + if (i == ppd->num_sizes) + return (NULL); + + /* + * Variable size; size name can be one of the following: + * + * Custom.WIDTHxLENGTHin - Size in inches + * Custom.WIDTHxLENGTHcm - Size in centimeters + * Custom.WIDTHxLENGTHmm - Size in millimeters + * Custom.WIDTHxLENGTH[pt] - Size in points + */ + + units[0] = '\0'; + if (sscanf(name + 7, "%fx%f%254s", &w, &l, units) < 2) + return (NULL); + + if (strcasecmp(units, "in") == 0) + { + ppd->sizes[i].width = w * 72.0f; + ppd->sizes[i].length = l * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "cm") == 0) + { + ppd->sizes[i].width = w / 2.54f * 72.0f; + ppd->sizes[i].length = l / 2.54f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 2.54f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 2.54f * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "mm") == 0) + { + ppd->sizes[i].width = w / 25.4f * 72.0f; + ppd->sizes[i].length = l / 25.4f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 25.4f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 25.4f * 72.0f - ppd->custom_margins[3]; + } + else + { + ppd->sizes[i].width = w; + ppd->sizes[i].length = l; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w - ppd->custom_margins[2]; + ppd->sizes[i].top = l - ppd->custom_margins[3]; + } + + return (ppd->sizes + i); + } + else + { + /* + * Lookup by name... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp(name, ppd->sizes[i].name) == 0) + return (ppd->sizes + i); + } + } + else + { + /* + * Find default... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (ppd->sizes[i].marked) + return (ppd->sizes + i); + } + + return (NULL); +} + + +/* + * 'ppdPageWidth()' - Get the page width for the given size. + */ + +float /* O - Width of page in points or 0.0 */ +ppdPageWidth(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->width); +} + + +/* + * 'ppdPageLength()' - Get the page length for the given size. + */ + +float /* O - Length of page in points or 0.0 */ +ppdPageLength(ppd_file_t *ppd, /* I - PPD file */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->length); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ppd.c b/cups/ppd.c new file mode 100644 index 0000000000..94962541ed --- /dev/null +++ b/cups/ppd.c @@ -0,0 +1,1939 @@ +/* + * "$Id$" + * + * PPD file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * Contents: + * + * ppdClose() - Free all memory used by the PPD file. + * ppd_free_group() - Free a single UI group. + * ppd_free_option() - Free a single option. + * ppdOpen() - Read a PPD file into memory. + * ppdOpenFd() - Read a PPD file into memory. + * ppdOpenFile() - Read a PPD file into memory. + * ppd_read() - Read a line from a PPD file, skipping comment lines + * as necessary. + * compare_strings() - Compare two strings. + * compare_groups() - Compare two groups. + * compare_options() - Compare two options. + * compare_choices() - Compare two choices. + */ + +/* + * Include necessary headers. + */ + +#include "ppd.h" +#include +#include +#include "string.h" +#include "language.h" +#include "debug.h" + + +/* + * Definitions... + */ + +#if defined(WIN32) || defined(__EMX__) +# define READ_BINARY "rb" /* Open a binary file for reading */ +# define WRITE_BINARY "wb" /* Open a binary file for writing */ +#else +# define READ_BINARY "r" /* Open a binary file for reading */ +# define WRITE_BINARY "w" /* Open a binary file for writing */ +#endif /* WIN32 || __EMX__ */ + +#define safe_free(p) if (p) free(p) /* Safe free macro */ + +#define PPD_KEYWORD 1 /* Line contained a keyword */ +#define PPD_OPTION 2 /* Line contained an option name */ +#define PPD_TEXT 4 /* Line contained human-readable text */ +#define PPD_STRING 8 /* Line contained a string or code */ + + +/* + * Local functions... + */ + +static int compare_strings(char *s, char *t); +static int compare_groups(ppd_group_t *g0, ppd_group_t *g1); +static int compare_options(ppd_option_t *o0, ppd_option_t *o1); +static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1); +static int ppd_read(FILE *fp, char *keyword, char *option, + char *text, char **string); +static void ppd_decode(char *string); +static void ppd_fix(char *string); +static void ppd_free_group(ppd_group_t *group); +static void ppd_free_option(ppd_option_t *option); +static ppd_group_t *ppd_get_group(ppd_file_t *ppd, char *name); +static ppd_option_t *ppd_get_option(ppd_group_t *group, char *name); +static ppd_choice_t *ppd_add_choice(ppd_option_t *option, char *name); + + +/* + * 'ppdClose()' - Free all memory used by the PPD file. + */ + +void +ppdClose(ppd_file_t *ppd) /* I - PPD file record */ +{ + int i; /* Looping var */ + ppd_emul_t *emul; /* Current emulation */ + ppd_group_t *group; /* Current group */ + char **font; /* Current font */ + char **filter; /* Current filter */ + + + /* + * Range check the PPD file record... + */ + + if (ppd == NULL) + return; + + /* + * Free all strings at the top level... + */ + + safe_free(ppd->patches); + safe_free(ppd->jcl_begin); + safe_free(ppd->jcl_ps); + safe_free(ppd->jcl_end); + safe_free(ppd->lang_encoding); + safe_free(ppd->lang_version); + safe_free(ppd->modelname); + safe_free(ppd->ttrasterizer); + safe_free(ppd->manufacturer); + safe_free(ppd->product); + safe_free(ppd->nickname); + safe_free(ppd->shortnickname); + + /* + * Free any emulations... + */ + + if (ppd->num_emulations > 0) + { + for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++) + { + safe_free(emul->start); + safe_free(emul->stop); + } + + safe_free(ppd->emulations); + } + + /* + * Free any UI groups, subgroups, and options... + */ + + if (ppd->num_groups > 0) + { + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + ppd_free_group(group); + + safe_free(ppd->groups); + } + + /* + * Free any page sizes... + */ + + if (ppd->num_sizes > 0) + safe_free(ppd->sizes); + + /* + * Free any constraints... + */ + + if (ppd->num_consts > 0) + safe_free(ppd->consts); + + /* + * Free any filters... + */ + + if (ppd->num_filters > 0) + { + for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++) + safe_free(*filter); + + safe_free(ppd->filters); + } + + /* + * Free any fonts... + */ + + if (ppd->num_fonts > 0) + { + for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++) + safe_free(*font); + + safe_free(ppd->fonts); + } + + /* + * Free any profiles... + */ + + if (ppd->num_profiles > 0) + safe_free(ppd->profiles); + + /* + * Free the whole record... + */ + + safe_free(ppd); +} + + +/* + * 'ppd_free_group()' - Free a single UI group. + */ + +static void +ppd_free_group(ppd_group_t *group) /* I - Group to free */ +{ + int i; /* Looping var */ + ppd_option_t *option; /* Current option */ + ppd_group_t *subgroup; /* Current sub-group */ + + + if (group->num_options > 0) + { + for (i = group->num_options, option = group->options; + i > 0; + i --, option ++) + ppd_free_option(option); + + safe_free(group->options); + } + + if (group->num_subgroups > 0) + { + for (i = group->num_subgroups, subgroup = group->subgroups; + i > 0; + i --, subgroup ++) + ppd_free_group(subgroup); + + safe_free(group->subgroups); + } +} + + +/* + * 'ppd_free_option()' - Free a single option. + */ + +static void +ppd_free_option(ppd_option_t *option) /* I - Option to free */ +{ + int i; /* Looping var */ + ppd_choice_t *choice; /* Current choice */ + + + if (option->num_choices > 0) + { + for (i = option->num_choices, choice = option->choices; + i > 0; + i --, choice ++) + safe_free(choice->code); + + safe_free(option->choices); + } +} + + +/* + * 'ppd_get_group()' - Find or create the named group as needed. + */ + +static ppd_group_t * /* O - Named group */ +ppd_get_group(ppd_file_t *ppd, /* I - PPD file */ + char *name) /* I - Name of group */ +{ + int i; /* Looping var */ + ppd_group_t *group; /* Group */ + + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + if (strcmp(group->text, name) == 0) + break; + + if (i == 0) + { + if (ppd->num_groups == 0) + group = malloc(sizeof(ppd_group_t)); + else + group = realloc(ppd->groups, + (ppd->num_groups + 1) * sizeof(ppd_group_t)); + + if (group == NULL) + return (NULL); + + ppd->groups = group; + group += ppd->num_groups; + ppd->num_groups ++; + + memset(group, 0, sizeof(ppd_group_t)); + strncpy(group->text, name, sizeof(group->text) - 1); + } + + return (group); +} + + +/* + * 'ppd_get_option()' - Find or create the named option as needed. + */ + +static ppd_option_t * /* O - Named option */ +ppd_get_option(ppd_group_t *group, /* I - Group */ + char *name) /* I - Name of option */ +{ + int i; /* Looping var */ + ppd_option_t *option; /* Option */ + + + for (i = group->num_options, option = group->options; i > 0; i --, option ++) + if (strcmp(option->keyword, name) == 0) + break; + + if (i == 0) + { + if (group->num_options == 0) + option = malloc(sizeof(ppd_option_t)); + else + option = realloc(group->options, + (group->num_options + 1) * sizeof(ppd_option_t)); + + if (option == NULL) + return (NULL); + + group->options = option; + option += group->num_options; + group->num_options ++; + + memset(option, 0, sizeof(ppd_option_t)); + strncpy(option->keyword, name, sizeof(option->keyword) - 1); + } + + return (option); +} + + +/* + * 'ppd_add_choice()' - Add a choice to an option. + */ + +static ppd_choice_t * /* O - Named choice */ +ppd_add_choice(ppd_option_t *option, /* I - Option */ + char *name) /* I - Name of choice */ +{ + ppd_choice_t *choice; /* Choice */ + + + if (option->num_choices == 0) + choice = malloc(sizeof(ppd_choice_t)); + else + choice = realloc(option->choices, + sizeof(ppd_choice_t) * (option->num_choices + 1)); + + if (choice == NULL) + return (NULL); + + option->choices = choice; + choice += option->num_choices; + option->num_choices ++; + + memset(choice, 0, sizeof(ppd_choice_t)); + strncpy(choice->choice, name, sizeof(choice->choice) - 1); + + return (choice); +} + + +/* + * 'ppd_add_size()' - Add a page size. + */ + +static ppd_size_t * /* O - Named size */ +ppd_add_size(ppd_file_t *ppd, /* I - PPD file */ + char *name) /* I - Name of size */ +{ + ppd_size_t *size; /* Size */ + + + if (ppd->num_sizes == 0) + size = malloc(sizeof(ppd_size_t)); + else + size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1)); + + if (size == NULL) + return (NULL); + + ppd->sizes = size; + size += ppd->num_sizes; + ppd->num_sizes ++; + + memset(size, 0, sizeof(ppd_size_t)); + strncpy(size->name, name, sizeof(size->name) - 1); + + return (size); +} + + +/* + * 'ppdOpen()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpen(FILE *fp) /* I - File to read from */ +{ + int i, j, k, m; /* Looping vars */ + int count; /* Temporary count */ + ppd_file_t *ppd; /* PPD file record */ + ppd_group_t *group, /* Current group */ + *subgroup; /* Current sub-group */ + ppd_option_t *option; /* Current option */ + ppd_choice_t *choice; /* Current choice */ + ppd_const_t *constraint; /* Current constraint */ + ppd_size_t *size; /* Current page size */ + int mask; /* Line data mask */ + char keyword[PPD_MAX_NAME], + /* Keyword from file */ + name[PPD_MAX_NAME], + /* Option from file */ + text[PPD_MAX_TEXT], + /* Human-readable text from file */ + *string, /* Code/text from file */ + *sptr, /* Pointer into string */ + *nameptr, /* Pointer into name */ + *temp, /* Temporary string pointer */ + **tempfonts; /* Temporary fonts pointer */ + float order; /* Order dependency number */ + ppd_section_t section; /* Order dependency section */ + ppd_profile_t *profile; /* Pointer to color profile */ + char **filter; /* Pointer to filter */ + cups_lang_t *language; /* Default language */ + + + /* + * Get the default language for the user... + */ + + language = cupsLangDefault(); + + /* + * Range check input... + */ + + if (fp == NULL) + return (NULL); + + /* + * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'... + */ + + mask = ppd_read(fp, keyword, name, text, &string); + + if (mask == 0 || + strcmp(keyword, "PPD-Adobe") != 0 || + string == NULL || string[0] != '4') + { + /* + * Either this is not a PPD file, or it is not a 4.x PPD file. + */ + + safe_free(string); + + return (NULL); + } + + DEBUG_printf(("ppdOpen: keyword = %s, string = %08x\n", keyword, string)); + + safe_free(string); + + /* + * Allocate memory for the PPD file record... + */ + + if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL) + return (NULL); + + ppd->language_level = 1; + ppd->color_device = 0; + ppd->colorspace = PPD_CS_GRAY; + ppd->landscape = 90; + + /* + * Read lines from the PPD file and add them to the file record... + */ + + group = NULL; + subgroup = NULL; + option = NULL; + choice = NULL; + + while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0) + { +#ifdef DEBUG + printf("mask = %x, keyword = \"%s\"", mask, keyword); + + if (name[0] != '\0') + printf(", name = \"%s\"", name); + + if (text[0] != '\0') + printf(", text = \"%s\"", text); + + if (string != NULL) + { + if (strlen(string) > 40) + printf(", string = %08x", string); + else + printf(", string = \"%s\"", string); + } + + puts(""); +#endif /* DEBUG */ + + if (strcmp(keyword, "LanguageLevel") == 0) + ppd->language_level = atoi(string); + else if (strcmp(keyword, "LanguageEncoding") == 0) + { + ppd->lang_encoding = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "LanguageVersion") == 0) + { + ppd->lang_version = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "Manufacturer") == 0) + { + ppd->manufacturer = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "ModelName") == 0) + { + ppd->modelname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "NickName") == 0) + { + ppd->nickname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "Product") == 0) + { + ppd->product = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "ShortNickName") == 0) + { + ppd->shortnickname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "TTRasterizer") == 0) + { + ppd->ttrasterizer = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLBegin") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_begin = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLEnd") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_end = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLToPSInterpreter") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_ps = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "AccurateScreensSupport") == 0) + ppd->accurate_screens = strcmp(string, "True") == 0; + else if (strcmp(keyword, "ColorDevice") == 0) + ppd->color_device = strcmp(string, "True") == 0; + else if (strcmp(keyword, "ContoneOnly") == 0) + ppd->contone_only = strcmp(string, "True") == 0; + else if (strcmp(keyword, "DefaultColorSpace") == 0) + { + if (strcmp(string, "CMY") == 0) + ppd->colorspace = PPD_CS_CMY; + else if (strcmp(string, "CMYK") == 0) + ppd->colorspace = PPD_CS_CMYK; + else if (strcmp(string, "RGB") == 0) + ppd->colorspace = PPD_CS_RGB; + else if (strcmp(string, "RGBK") == 0) + ppd->colorspace = PPD_CS_RGBK; + else if (strcmp(string, "N") == 0) + ppd->colorspace = PPD_CS_N; + else + ppd->colorspace = PPD_CS_GRAY; + } + else if (strcmp(keyword, "cupsFlipDuplex") == 0) + ppd->flip_duplex = strcmp(string, "True") == 0; + else if (strcmp(keyword, "cupsManualCopies") == 0) + ppd->manual_copies = strcmp(string, "True") == 0; + else if (strcmp(keyword, "cupsModelNumber") == 0) + ppd->model_number = atoi(string); + else if (strcmp(keyword, "cupsColorProfile") == 0) + { + if (ppd->num_profiles == 0) + profile = malloc(sizeof(ppd_profile_t)); + else + profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * + (ppd->num_profiles + 1)); + + ppd->profiles = profile; + profile += ppd->num_profiles; + ppd->num_profiles ++; + + memset(profile, 0, sizeof(ppd_profile_t)); + strncpy(profile->resolution, name, sizeof(profile->resolution) - 1); + strncpy(profile->media_type, text, sizeof(profile->media_type) - 1); + sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density), + &(profile->gamma), + profile->matrix[0] + 0, profile->matrix[0] + 1, + profile->matrix[0] + 2, profile->matrix[1] + 0, + profile->matrix[1] + 1, profile->matrix[1] + 2, + profile->matrix[2] + 0, profile->matrix[2] + 1, + profile->matrix[2] + 2); + } + else if (strcmp(keyword, "cupsFilter") == 0) + { + if (ppd->num_filters == 0) + filter = malloc(sizeof(char *)); + else + filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1)); + + if (filter == NULL) + { + safe_free(filter); + ppdClose(ppd); + return (NULL); + } + + ppd->filters = filter; + filter += ppd->num_filters; + ppd->num_filters ++; + + /* + * Copy filter string and prevent it from being freed below... + */ + + *filter = string; + string = NULL; + } + else if (strcmp(keyword, "Throughput") == 0) + ppd->throughput = atoi(string); + else if (strcmp(keyword, "Font") == 0) + { + /* + * Add this font to the list of available fonts... + */ + + if (ppd->num_fonts == 0) + tempfonts = (char **)malloc(sizeof(char *)); + else + tempfonts = (char **)realloc(ppd->fonts, + sizeof(char *) * (ppd->num_fonts + 1)); + + if (tempfonts == NULL) + { + safe_free(string); + ppdClose(ppd); + return (NULL); + } + + ppd->fonts = tempfonts; + ppd->fonts[ppd->num_fonts] = strdup(name); + ppd->num_fonts ++; + } + else if (strcmp(keyword, "VariablePaperSize") == 0 && + strcmp(string, "True") == 0 && + !ppd->variable_sizes) + { + ppd->variable_sizes = 1; + + /* + * Add a "Custom" page size entry... + */ + + ppd_add_size(ppd, "Custom"); + + /* + * Add a "Custom" page size option... + */ + + if ((option = ppdFindOption(ppd, "PageSize")) == NULL) + { + ppd_group_t *temp; + + + if ((temp = ppd_get_group(ppd, + cupsLangString(language, + CUPS_MSG_GENERAL))) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((option = ppd_get_option(temp, "PageSize")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + } + + if ((choice = ppd_add_choice(option, "Custom")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE), + sizeof(choice->text) - 1); + option = NULL; + } + else if (strcmp(keyword, "MaxMediaWidth") == 0) + ppd->custom_max[0] = (float)atof(string); + else if (strcmp(keyword, "MaxMediaHeight") == 0) + ppd->custom_max[1] = (float)atof(string); + else if (strcmp(keyword, "ParamCustomPageSize") == 0) + { + if (strcmp(name, "Width") == 0) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0, + ppd->custom_max + 0); + else if (strcmp(name, "Height") == 0) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1, + ppd->custom_max + 1); + } + else if (strcmp(keyword, "HWMargins") == 0) + sscanf(string, "%f%f%f%f", ppd->custom_margins + 0, + ppd->custom_margins + 1, ppd->custom_margins + 2, + ppd->custom_margins + 3); + else if (strcmp(keyword, "CustomPageSize") == 0 && + strcmp(name, "True") == 0) + { + if (!ppd->variable_sizes) + { + ppd->variable_sizes = 1; + + /* + * Add a "Custom" page size entry... + */ + + ppd_add_size(ppd, "Custom"); + + /* + * Add a "Custom" page size option... + */ + + if ((option = ppdFindOption(ppd, "PageSize")) == NULL) + { + ppd_group_t *temp; + + + if ((temp = ppd_get_group(ppd, + cupsLangString(language, + CUPS_MSG_GENERAL))) == NULL) + { + DEBUG_puts("Unable to get general group!"); + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((option = ppd_get_option(temp, "PageSize")) == NULL) + { + DEBUG_puts("Unable to get PageSize option!"); + ppdClose(ppd); + safe_free(string); + return (NULL); + } + } + + if ((choice = ppd_add_choice(option, "Custom")) == NULL) + { + DEBUG_puts("Unable to add Custom choice!"); + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE), + sizeof(choice->text) - 1); + option = NULL; + } + + if ((option = ppdFindOption(ppd, "PageSize")) == NULL) + { + DEBUG_puts("Unable to find PageSize option!"); + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((choice = ppdFindChoice(option, "Custom")) == NULL) + { + DEBUG_puts("Unable to find Custom choice!"); + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + choice->code = string; + string = NULL; + option = NULL; + } + else if (strcmp(keyword, "LandscapeOrientation") == 0) + { + if (strcmp(string, "Minus90") == 0) + ppd->landscape = -90; + else + ppd->landscape = 90; + } + else if (strcmp(keyword, "Emulators") == 0) + { + for (count = 1, sptr = string; sptr != NULL;) + if ((sptr = strchr(sptr, ' ')) != NULL) + { + count ++; + while (*sptr == ' ') + sptr ++; + } + + ppd->num_emulations = count; + ppd->emulations = calloc(sizeof(ppd_emul_t), count); + + for (i = 0, sptr = string; i < count; i ++) + { + for (nameptr = ppd->emulations[i].name; + *sptr != '\0' && *sptr != ' '; + sptr ++) + if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1)) + *nameptr++ = *sptr; + + *nameptr = '\0'; + + while (*sptr == ' ') + sptr ++; + } + } + else if (strncmp(keyword, "StartEmulator_", 14) == 0) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (strcmp(keyword + 14, ppd->emulations[i].name) == 0) + { + ppd->emulations[i].start = string; + string = NULL; + } + } + else if (strncmp(keyword, "StopEmulator_", 13) == 0) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (strcmp(keyword + 13, ppd->emulations[i].name) == 0) + { + ppd->emulations[i].stop = string; + string = NULL; + } + } + else if (strcmp(keyword, "JobPatchFile") == 0) + { + if (ppd->patches == NULL) + { + ppd->patches = string; + string = NULL; + } + else + { + temp = realloc(ppd->patches, strlen(ppd->patches) + + strlen(string) + 1); + if (temp == NULL) + { + safe_free(string); + ppdClose(ppd); + return (NULL); + } + + ppd->patches = temp; + + strcpy(ppd->patches + strlen(ppd->patches), string); + } + } + else if (strcmp(keyword, "OpenUI") == 0) + { + /* + * Add an option record to the current sub-group, group, or file... + */ + + if (name[0] == '*') + strcpy(name, name + 1); + + if (string == NULL) + { + ppdClose(ppd); + return (NULL); + } + + if (subgroup != NULL) + option = ppd_get_option(subgroup, name); + else if (group == NULL) + { + if (strcmp(name, "Collate") != 0 && + strcmp(name, "Duplex") != 0 && + strcmp(name, "InputSlot") != 0 && + strcmp(name, "ManualFeed") != 0 && + strcmp(name, "MediaType") != 0 && + strcmp(name, "MediaColor") != 0 && + strcmp(name, "MediaWeight") != 0 && + strcmp(name, "OutputBin") != 0 && + strcmp(name, "OutputMode") != 0 && + strcmp(name, "OutputOrder") != 0 && + strcmp(name, "PageSize") != 0 && + strcmp(name, "PageRegion") != 0) + group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_EXTRA)); + else + group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_GENERAL)); + + if (group == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + option = ppd_get_option(group, name); + group = NULL; + } + else + option = ppd_get_option(group, name); + + if (option == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Now fill in the initial information for the option... + */ + + if (strcmp(string, "PickMany") == 0) + option->ui = PPD_UI_PICKMANY; + else if (strcmp(string, "Boolean") == 0) + option->ui = PPD_UI_BOOLEAN; + else + option->ui = PPD_UI_PICKONE; + + if (text[0]) + { + strncpy(option->text, text, sizeof(option->text) - 1); + ppd_fix(option->text); + } + else + { + if (strcmp(name, "PageSize") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE), + sizeof(option->text) - 1); + else if (strcmp(name, "MediaType") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE), + sizeof(option->text) - 1); + else if (strcmp(name, "InputSlot") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE), + sizeof(option->text) - 1); + else if (strcmp(name, "ColorModel") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE), + sizeof(option->text) - 1); + else if (strcmp(name, "Resolution") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION), + sizeof(option->text) - 1); + else + strncpy(option->text, name, sizeof(option->text) - 1); + } + + option->section = PPD_ORDER_ANY; + } + else if (strcmp(keyword, "JCLOpenUI") == 0) + { + /* + * Find the JCL group, and add if needed... + */ + + group = ppd_get_group(ppd, "JCL"); + + if (group == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Add an option record to the current JCLs... + */ + + if (name[0] == '*') + strcpy(name, name + 1); + + option = ppd_get_option(group, name); + + if (option == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Now fill in the initial information for the option... + */ + + if (strcmp(string, "PickMany") == 0) + option->ui = PPD_UI_PICKMANY; + else if (strcmp(string, "Boolean") == 0) + option->ui = PPD_UI_BOOLEAN; + else + option->ui = PPD_UI_PICKONE; + + strncpy(option->text, text, sizeof(option->text) - 1); + + option->section = PPD_ORDER_JCL; + group = NULL; + } + else if (strcmp(keyword, "CloseUI") == 0 || + strcmp(keyword, "JCLCloseUI") == 0) + option = NULL; + else if (strcmp(keyword, "OpenGroup") == 0) + { + /* + * Open a new group... + */ + + if (group != NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if (strchr(string, '/') != NULL) /* Just show human readable text */ + strcpy(string, strchr(string, '/') + 1); + + ppd_decode(string); + ppd_fix(string); + group = ppd_get_group(ppd, string); + } + else if (strcmp(keyword, "CloseGroup") == 0) + group = NULL; + else if (strcmp(keyword, "OrderDependency") == 0 || + strcmp(keyword, "NonUIOrderDependency") == 0) + { + if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if (keyword[0] == '*') + strcpy(keyword, keyword + 1); + + if (strcmp(name, "ExitServer") == 0) + section = PPD_ORDER_EXIT; + else if (strcmp(name, "Prolog") == 0) + section = PPD_ORDER_PROLOG; + else if (strcmp(name, "DocumentSetup") == 0) + section = PPD_ORDER_DOCUMENT; + else if (strcmp(name, "PageSetup") == 0) + section = PPD_ORDER_PAGE; + else if (strcmp(name, "JCLSetup") == 0) + section = PPD_ORDER_JCL; + else + section = PPD_ORDER_ANY; + + if (option == NULL) + { + ppd_group_t *temp; + + + /* + * Only valid for Non-UI options... + */ + + for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++) + if (temp->text[0] == '\0') + break; + + if (i > 0) + for (i = 0; i < temp->num_options; i ++) + if (strcmp(keyword, temp->options[i].keyword) == 0) + { + temp->options[i].section = section; + temp->options[i].order = order; + break; + } + } + else + { + option->section = section; + option->order = order; + } + } + else if (strncmp(keyword, "Default", 7) == 0) + { + if (string == NULL) + continue; + + if (strchr(string, '/') != NULL) + *strchr(string, '/') = '\0'; + + if (option == NULL) + { + ppd_group_t *temp; + + + /* + * Only valid for Non-UI options... + */ + + for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++) + if (temp->text[0] == '\0') + break; + + if (i > 0) + for (i = 0; i < temp->num_options; i ++) + if (strcmp(keyword, temp->options[i].keyword) == 0) + { + strncpy(temp->options[i].defchoice, string, + sizeof(temp->options[i].defchoice) - 1); + break; + } + } + else + strncpy(option->defchoice, string, sizeof(option->defchoice) - 1); + } + else if (strcmp(keyword, "UIConstraints") == 0 || + strcmp(keyword, "NonUIConstraints") == 0) + { + if (ppd->num_consts == 0) + constraint = calloc(sizeof(ppd_const_t), 1); + else + constraint = realloc(ppd->consts, + (ppd->num_consts + 1) * sizeof(ppd_const_t)); + + if (constraint == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + ppd->consts = constraint; + constraint += ppd->num_consts; + ppd->num_consts ++; + + switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1, + constraint->choice1, constraint->option2, + constraint->choice2)) + { + case 0 : /* Error */ + case 1 : /* Error */ + ppdClose(ppd); + safe_free(string); + break; + + case 2 : /* Two options... */ + /* + * The following strcpy's are safe, as optionN and + * choiceN are all the same size (size defined by PPD spec...) + */ + + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + strcpy(constraint->option2, constraint->choice1 + 1); + else + strcpy(constraint->option2, constraint->choice1); + + constraint->choice1[0] = '\0'; + constraint->choice2[0] = '\0'; + break; + + case 3 : /* Two options, one choice... */ + /* + * The following strcpy's are safe, as optionN and + * choiceN are all the same size (size defined by PPD spec...) + */ + + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + { + strcpy(constraint->choice2, constraint->option2); + strcpy(constraint->option2, constraint->choice1 + 1); + constraint->choice1[0] = '\0'; + } + else + { + if (constraint->option2[0] == '*') + strcpy(constraint->option2, constraint->option2 + 1); + + constraint->choice2[0] = '\0'; + } + break; + + case 4 : /* Two options, two choices... */ + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->option2[0] == '*') + strcpy(constraint->option2, constraint->option2 + 1); + break; + } + } + else if (strcmp(keyword, "PaperDimension") == 0) + { + if ((size = ppdPageSize(ppd, name)) != NULL) + sscanf(string, "%f%f", &(size->width), &(size->length)); + } + else if (strcmp(keyword, "ImageableArea") == 0) + { + if ((size = ppdPageSize(ppd, name)) != NULL) + sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom), + &(size->right), &(size->top)); + } + else if (option != NULL && + (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) == + (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) + { + DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup)); + + if (strcmp(keyword, "PageSize") == 0) + { + /* + * Add a page size... + */ + + ppd_add_size(ppd, name); + } + + /* + * Add the option choice... + */ + + choice = ppd_add_choice(option, name); + + if (mask & PPD_TEXT) + { + strncpy(choice->text, text, sizeof(choice->text) - 1); + ppd_fix(choice->text); + } + else if (strcmp(name, "True") == 0) + strcpy(choice->text, "Yes"); + else if (strcmp(name, "False") == 0) + strcpy(choice->text, "No"); + else + strncpy(choice->text, name, sizeof(choice->text) - 1); + + if (strncmp(keyword, "JCL", 3) == 0) + ppd_decode(string); /* Decode quoted string */ + + choice->code = string; + string = NULL; /* Don't free this string below */ + } + + safe_free(string); + } + +#ifdef DEBUG + if (!feof(fp)) + printf("Premature EOF at %d...\n", ftell(fp)); +#endif /* DEBUG */ + + /* + * Set the option back-pointer for each choice... + */ + + qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))compare_groups); + + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + qsort(group->options, group->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))compare_options); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + qsort(option->choices, option->num_choices, sizeof(ppd_choice_t), + (int (*)(const void *, const void *))compare_choices); + + for (k = 0; k < option->num_choices; k ++) + option->choices[k].option = (void *)option; + } + + qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))compare_groups); + + for (j = group->num_subgroups, subgroup = group->subgroups; + j > 0; + j --, subgroup ++) + { + qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))compare_options); + + for (k = group->num_options, option = group->options; + k > 0; + k --, option ++) + { + qsort(option->choices, option->num_choices, sizeof(ppd_choice_t), + (int (*)(const void *, const void *))compare_choices); + + for (m = 0; m < option->num_choices; m ++) + option->choices[m].option = (void *)option; + } + } + } + + return (ppd); +} + + +/* + * 'ppdOpenFd()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpenFd(int fd) /* I - File to read from */ +{ + FILE *fp; /* File pointer */ + ppd_file_t *ppd; /* PPD file record */ + + + /* + * Range check input... + */ + + if (fd < 0) + return (NULL); + + /* + * Try to open the file and parse it... + */ + + if ((fp = fdopen(fd, "r")) != NULL) + { + setbuf(fp, NULL); + + ppd = ppdOpen(fp); + + safe_free(fp); + } + else + ppd = NULL; + + return (ppd); +} + + +/* + * 'ppdOpenFile()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpenFile(const char *filename) /* I - File to read from */ +{ + FILE *fp; /* File pointer */ + ppd_file_t *ppd; /* PPD file record */ + + + /* + * Range check input... + */ + + if (filename == NULL) + return (NULL); + + /* + * Try to open the file and parse it... + */ + + if ((fp = fopen(filename, "r")) != NULL) + { + ppd = ppdOpen(fp); + + fclose(fp); + } + else + ppd = NULL; + + return (ppd); +} + + +/* + * 'compare_strings()' - Compare two strings. + */ + +static int /* O - Result of comparison */ +compare_strings(char *s, /* I - First string */ + char *t) /* I - Second string */ +{ + int diff, /* Difference between digits */ + digits; /* Number of digits */ + + + /* + * Loop through both strings, returning only when a difference is + * seen. Also, compare whole numbers rather than just characters, too! + */ + + while (*s && *t) + { + if (isdigit(*s) && isdigit(*t)) + { + /* + * Got a number; start by skipping leading 0's... + */ + + while (*s == '0') + s ++; + while (*t == '0') + t ++; + + /* + * Skip equal digits... + */ + + while (isdigit(*s) && *s == *t) + { + s ++; + t ++; + } + + /* + * Bounce out if *s and *t aren't both digits... + */ + + if (isdigit(*s) && !isdigit(*t)) + return (1); + else if (!isdigit(*s) && isdigit(*t)) + return (-1); + else if (!isdigit(*s) || !isdigit(*t)) + continue; + + if (*s < *t) + diff = -1; + else + diff = 1; + + /* + * Figure out how many more digits there are... + */ + + digits = 0; + + while (isdigit(*s)) + { + digits ++; + s ++; + } + + while (isdigit(*t)) + { + digits --; + t ++; + } + + /* + * Return if the number or value of the digits is different... + */ + + if (digits < 0) + return (-1); + else if (digits > 0) + return (1); + else + return (diff); + } + else if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + else + { + s ++; + t ++; + } + } + + /* + * Return the results of the final comparison... + */ + + if (*s) + return (1); + else if (*t) + return (-1); + else + return (0); +} + + +/* + * 'compare_groups()' - Compare two groups. + */ + +static int /* O - Result of comparison */ +compare_groups(ppd_group_t *g0, /* I - First group */ + ppd_group_t *g1) /* I - Second group */ +{ + return (compare_strings(g0->text, g1->text)); +} + + +/* + * 'compare_options()' - Compare two options. + */ + +static int /* O - Result of comparison */ +compare_options(ppd_option_t *o0,/* I - First option */ + ppd_option_t *o1)/* I - Second option */ +{ + return (compare_strings(o0->text, o1->text)); +} + + +/* + * 'compare_choices()' - Compare two choices. + */ + +static int /* O - Result of comparison */ +compare_choices(ppd_choice_t *c0,/* I - First choice */ + ppd_choice_t *c1)/* I - Second choice */ +{ + return (compare_strings(c0->text, c1->text)); +} + + +/* + * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as + * necessary. + */ + +static int /* O - Bitmask of fields read */ +ppd_read(FILE *fp, /* I - File to read from */ + char *keyword, /* O - Keyword from line */ + char *option, /* O - Option from line */ + char *text, /* O - Human-readable text from line */ + char **string) /* O - Code/string data */ +{ + int ch, /* Character from file */ + endquote, /* Waiting for an end quote */ + mask; /* Mask to be returned */ + char *keyptr, /* Keyword pointer */ + *optptr, /* Option pointer */ + *textptr, /* Text pointer */ + *strptr, /* Pointer into string */ + *lineptr, /* Current position in line buffer */ + line[65536]; /* Line buffer (64k) */ + + + /* + * Range check everything... + */ + + if (fp == NULL || keyword == NULL || option == NULL || text == NULL || + string == NULL) + return (0); + + /* + * Now loop until we have a valid line... + */ + + *string = NULL; + + do + { + /* + * Read the line... + */ + + lineptr = line; + endquote = 0; + + while ((ch = getc(fp)) != EOF && + (lineptr - line) < (sizeof(line) - 1)) + { + if (ch == '\r' || ch == '\n') + { + /* + * Line feed or carriage return... + */ + + if (lineptr == line) /* Skip blank lines */ + continue; + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = getc(fp)) == EOF) + break; + if (ch != 0x0a) + ungetc(ch, fp); + } + + ch = '\n'; + + if (!endquote) /* Continue for multi-line text */ + break; + + *lineptr++ = '\n'; + } + else + { + /* + * Any other character... + */ + + *lineptr++ = ch; + + if (ch == '\"') + { + endquote = !endquote; + + if (!endquote) + { + /* + * End of quoted string; ignore trailing characters... + */ + + while ((ch = getc(fp)) != EOF) + if (ch == '\n') + break; + else if (ch == '\r') + { + ch = getc(fp); + if (ch != '\n') + ungetc(ch, fp); + break; + } + + break; + } + } + } + } + + if (endquote) + { + /* + * Didn't finish this quoted string... + */ + + while ((ch = getc(fp)) != EOF) + if (ch == '\"') + break; + } + + if (ch != '\n') + { + /* + * Didn't finish this line... + */ + + while ((ch = getc(fp)) != EOF) + if (ch == '\r' || ch == '\n') + { + /* + * Line feed or carriage return... + */ + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = getc(fp)) == EOF) + break; + if (ch != 0x0a) + ungetc(ch, fp); + } + + break; + } + } + + if (lineptr > line && lineptr[-1] == '\n') + lineptr --; + + *lineptr = '\0'; + + if (ch == EOF && lineptr == line) + return (0); + + /* + * Now parse it... + */ + + mask = 0; + lineptr = line + 1; + + keyword[0] = '\0'; + option[0] = '\0'; + text[0] = '\0'; + *string = NULL; + + if (line[0] != '*') /* All lines start with an asterisk */ + continue; + + if (strncmp(line, "*%", 2) == 0 || /* Comment line */ + strncmp(line, "*?", 2) == 0 || /* Query line */ + strcmp(line, "*End") == 0) /* End of multi-line string */ + continue; + + /* + * Get a keyword... + */ + + keyptr = keyword; + + while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr) && + (keyptr - keyword) < (PPD_MAX_NAME - 1)) + *keyptr++ = *lineptr++; + + *keyptr = '\0'; + mask |= PPD_KEYWORD; + + if (*lineptr == ' ' || *lineptr == '\t') + { + /* + * Get an option name... + */ + + while (*lineptr == ' ' || *lineptr == '\t') + lineptr ++; + + optptr = option; + + while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && + *lineptr != '/' && (optptr - option) < 40) + *optptr++ = *lineptr++; + + *optptr = '\0'; + mask |= PPD_OPTION; + + if (*lineptr == '/') + { + /* + * Get human-readable text... + */ + + lineptr ++; + + textptr = text; + + while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && + (textptr - text) < (PPD_MAX_TEXT - 1)) + *textptr++ = *lineptr++; + + *textptr = '\0'; + ppd_decode(text); + + mask |= PPD_TEXT; + } + } + + if (*lineptr == ':') + { + /* + * Get string... + */ + + *string = malloc(strlen(lineptr) + 1); + + while (*lineptr == ':' || isspace(*lineptr)) + lineptr ++; + + strptr = *string; + + while (*lineptr != '\0') + { + if (*lineptr != '\"') + *strptr++ = *lineptr++; + else + lineptr ++; + } + + *strptr = '\0'; + + mask |= PPD_STRING; + } + } + while (mask == 0); + + return (mask); +} + + +/* + * 'ppd_decode()' - Decode a string value... + */ + +static void +ppd_decode(char *string) /* I - String to decode */ +{ + char *inptr, /* Input pointer */ + *outptr; /* Output pointer */ + + + inptr = string; + outptr = string; + + while (*inptr != '\0') + if (*inptr == '<' && isxdigit(inptr[1])) + { + /* + * Convert hex to 8-bit values... + */ + + inptr ++; + while (isxdigit(*inptr)) + { + if (isalpha(*inptr)) + *outptr = (tolower(*inptr) - 'a' + 10) << 4; + else + *outptr = (*inptr - '0') << 4; + + inptr ++; + + if (isalpha(*inptr)) + *outptr |= tolower(*inptr) - 'a' + 10; + else + *outptr |= *inptr - '0'; + + inptr ++; + outptr ++; + } + + while (*inptr != '>' && *inptr != '\0') + inptr ++; + while (*inptr == '>') + inptr ++; + } + else + *outptr++ = *inptr++; + + *outptr = '\0'; +} + + +/* + * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be + * valid ISO-8859-1 characters... + */ + +static void +ppd_fix(char *string) /* IO - String to fix */ +{ + unsigned char *p; /* Pointer into string */ + static unsigned char lut[32] =/* Lookup table for characters */ + { + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 'l', + '`', + '\'', + '^', + '~', + 0x20, /* bar */ + 0x20, /* circumflex */ + 0x20, /* dot */ + 0x20, /* double dot */ + 0x20, + 0x20, /* circle */ + 0x20, /* ??? */ + 0x20, + '\"', /* should be right quotes */ + 0x20, /* ??? */ + 0x20 /* accent */ + }; + + + for (p = (unsigned char *)string; *p; p ++) + if (*p >= 0x80 && *p < 0xa0) + *p = lut[*p - 0x80]; +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ppd.h b/cups/ppd.h new file mode 100644 index 0000000000..193dbd6171 --- /dev/null +++ b/cups/ppd.h @@ -0,0 +1,268 @@ +/* + * "$Id$" + * + * PostScript Printer Description definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + */ + +#ifndef _CUPS_PPD_H_ +# define _CUPS_PPD_H_ + +/* + * Include necessary headers... + */ + +# include + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * PPD version... + */ + +# define PPD_VERSION 4.3 /* Kept in sync with Adobe version number */ + + +/* + * PPD size limits (defined in Adobe spec) + */ + +# define PPD_MAX_NAME 41 /* Maximum size of name + 1 for nul */ +# define PPD_MAX_TEXT 81 /* Maximum size of text + 1 for nul */ +# define PPD_MAX_LINE 256 /* Maximum size of line + 1 for nul */ + + +/* + * Types and structures... + */ + +typedef enum /**** UI types ****/ +{ + PPD_UI_BOOLEAN, /* True or False option */ + PPD_UI_PICKONE, /* Pick one from a list */ + PPD_UI_PICKMANY /* Pick zero or more from a list */ +} ppd_ui_t; + +typedef enum /**** Order dependency sections ****/ +{ + PPD_ORDER_ANY, /* Option code can be anywhere in the file */ + PPD_ORDER_DOCUMENT, /* ... must be in the DocumentSetup section */ + PPD_ORDER_EXIT, /* ... must be sent prior to the document */ + PPD_ORDER_JCL, /* ... must be sent as a JCL command */ + PPD_ORDER_PAGE, /* ... must be in the PageSetup section */ + PPD_ORDER_PROLOG /* ... must be in the Prolog section */ +} ppd_section_t; + +typedef enum /**** Colorspaces ****/ +{ + PPD_CS_CMYK = -4, /* CMYK colorspace */ + PPD_CS_CMY, /* CMY colorspace */ + PPD_CS_GRAY = 1, /* Grayscale colorspace */ + PPD_CS_RGB = 3, /* RGB colorspace */ + PPD_CS_RGBK, /* RGBK (K = gray) colorspace */ + PPD_CS_N /* DeviceN colorspace */ +} ppd_cs_t; + +typedef struct /**** Option choices ****/ +{ + char marked, /* 0 if not selected, 1 otherwise */ + choice[PPD_MAX_NAME], + /* Computer-readable option name */ + text[PPD_MAX_TEXT], + /* Human-readable option name */ + *code; /* Code to send for this option */ + void *option; /* Pointer to parent option structure */ +} ppd_choice_t; + +typedef struct /**** Options ****/ +{ + char conflicted, /* 0 if no conflicts exist, 1 otherwise */ + keyword[PPD_MAX_NAME], + /* Option keyword name ("PageSize", etc.) */ + defchoice[PPD_MAX_NAME], + /* Default option choice */ + text[PPD_MAX_TEXT]; + /* Human-readable text */ + ppd_ui_t ui; /* Type of UI option */ + ppd_section_t section; /* Section for command */ + float order; /* Order number */ + int num_choices; /* Number of option choices */ + ppd_choice_t *choices; /* Option choices */ +} ppd_option_t; + +typedef struct ppd_group_str /**** Groups ****/ +{ + char text[PPD_MAX_TEXT]; + /* Human-readable group name */ + int num_options; /* Number of options */ + ppd_option_t *options; /* Options */ + int num_subgroups; /* Number of sub-groups */ + struct ppd_group_str *subgroups; + /* Sub-groups (max depth = 1) */ +} ppd_group_t; + +typedef struct /**** Constraints ****/ +{ + char option1[PPD_MAX_NAME], + /* First keyword */ + choice1[PPD_MAX_NAME], + /* First option/choice (blank for all) */ + option2[PPD_MAX_NAME], + /* Second keyword */ + choice2[PPD_MAX_NAME]; + /* Second option/choice (blank for all) */ +} ppd_const_t; + +typedef struct /**** Page Sizes ****/ +{ + int marked; /* Page size selected? */ + char name[PPD_MAX_NAME]; + /* Media size option */ + float width, /* Width of media in points */ + length, /* Length of media in points */ + left, /* Left printable margin in points */ + bottom, /* Bottom printable margin in points */ + right, /* Right printable margin in points */ + top; /* Top printable margin in points */ +} ppd_size_t; + +typedef struct /**** Emulators ****/ +{ + char name[PPD_MAX_NAME], + /* Emulator name */ + *start, /* Code to switch to this emulation */ + *stop; /* Code to stop this emulation */ +} ppd_emul_t; + +typedef struct /**** sRGB Color Profiles ****/ +{ + char resolution[PPD_MAX_NAME], + /* Resolution or "-" */ + media_type[PPD_MAX_NAME]; + /* Media type of "-" */ + float density, /* Ink density to use */ + gamma, /* Gamma correction to use */ + matrix[3][3]; /* Transform matrix */ +} ppd_profile_t; + +typedef struct /**** Files ****/ +{ + int language_level, /* Language level of device */ + color_device, /* 1 = color device, 0 = grayscale */ + variable_sizes, /* 1 = supports variable sizes, 0 = doesn't */ + accurate_screens,/* 1 = supports accurate screens, 0 = not */ + contone_only, /* 1 = continuous tone only, 0 = not */ + landscape, /* -90 or 90 */ + model_number, /* Device-specific model number */ + manual_copies, /* 1 = Copies done manually, 0 = hardware */ + throughput; /* Pages per minute */ + ppd_cs_t colorspace; /* Default colorspace */ + char *patches; /* Patch commands to be sent to printer */ + int num_emulations; /* Number of emulations supported */ + ppd_emul_t *emulations; /* Emulations and the code to invoke them */ + char *jcl_begin, /* Start JCL commands */ + *jcl_ps, /* Enter PostScript interpreter */ + *jcl_end, /* End JCL commands */ + *lang_encoding, /* Language encoding */ + *lang_version, /* Language version (English, Spanish, etc.) */ + *modelname, /* Model name (general) */ + *ttrasterizer, /* Truetype rasterizer */ + *manufacturer, /* Manufacturer name */ + *product, /* Product name (from PS RIP/interpreter) */ + *nickname, /* Nickname (specific) */ + *shortnickname; /* Short version of nickname */ + int num_groups; /* Number of UI groups */ + ppd_group_t *groups; /* UI groups */ + int num_sizes; /* Number of page sizes */ + ppd_size_t *sizes; /* Page sizes */ + float custom_min[2], /* Minimum variable page size */ + custom_max[2], /* Maximum variable page size */ + custom_margins[4];/* Margins around page */ + int num_consts; /* Number of UI/Non-UI constraints */ + ppd_const_t *consts; /* UI/Non-UI constraints */ + int num_fonts; /* Number of pre-loaded fonts */ + char **fonts; /* Pre-loaded fonts */ + int num_profiles; /* Number of sRGB color profiles */ + ppd_profile_t *profiles; /* sRGB color profiles */ + int num_filters; /* Number of filters */ + char **filters; /* Filter strings... */ + int flip_duplex; /* 1 = Flip page for back sides */ +} ppd_file_t; + + +/* + * Prototypes... + */ + +extern void ppdClose(ppd_file_t *ppd); +extern int ppdCollect(ppd_file_t *ppd, ppd_section_t section, + ppd_choice_t ***choices); +extern int ppdConflicts(ppd_file_t *ppd); +extern int ppdEmit(ppd_file_t *ppd, FILE *fp, + ppd_section_t section); +extern int ppdEmitFd(ppd_file_t *ppd, int fd, + ppd_section_t section); +extern int ppdEmitJCL(ppd_file_t *ppd, FILE *fp, int job_id, + const char *user, const char *title); +extern int ppdIsMarked(ppd_file_t *ppd, const char *keyword, + const char *option); +extern void ppdMarkDefaults(ppd_file_t *ppd); +extern int ppdMarkOption(ppd_file_t *ppd, const char *keyword, + const char *option); +extern ppd_choice_t *ppdFindChoice(ppd_option_t *o, const char *option); +extern ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword); +extern ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword); +extern ppd_file_t *ppdOpen(FILE *fp); +extern ppd_file_t *ppdOpenFd(int fd); +extern ppd_file_t *ppdOpenFile(const char *filename); +extern float ppdPageLength(ppd_file_t *ppd, const char *name); +extern ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name); +extern float ppdPageWidth(ppd_file_t *ppd, const char *name); + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_PPD_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/snprintf.c b/cups/snprintf.c new file mode 100644 index 0000000000..90dc58806c --- /dev/null +++ b/cups/snprintf.c @@ -0,0 +1,287 @@ +/* + * "$Id$" + * + * snprintf functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * vsnprintf() - Format a string into a fixed size buffer. + * snprintf() - Format a string into a fixed size buffer. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "string.h" + + +#ifndef HAVE_VSNPRINTF +/* + * 'vsnprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +vsnprintf(char *buffer, /* O - Output buffer */ + size_t bufsize, /* O - Size of output buffer */ + const char *format, /* I - printf-style format string */ + va_list ap) /* I - Pointer to additional arguments */ +{ + char *bufptr, /* Pointer to position in buffer */ + *bufend, /* Pointer to end of buffer */ + sign, /* Sign of format width */ + size, /* Size character (h, l, L) */ + type; /* Format type character */ + const char *bufformat; /* Start of format */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + temp[1024]; /* Buffer for formatted numbers */ + int *chars; /* Pointer to integer for %p */ + char *s; /* Pointer to string */ + int slen; /* Length of string */ + + + /* + * Loop through the format string, formatting as needed... + */ + + bufptr = buffer; + bufend = buffer + bufsize - 1; + + while (*format && bufptr < bufend) + { + if (*format == '%') + { + bufformat = format; + format ++; + + if (*format == '%') + { + *bufptr++ = *format++; + continue; + } + else if (strchr(" -+#\'", *format)) + sign = *format++; + else + sign = 0; + + width = 0; + while (isdigit(*format)) + width = width * 10 + *format++ - '0'; + + if (*format == '.') + { + format ++; + prec = 0; + + while (isdigit(*format)) + prec = prec * 10 + *format++ - '0'; + } + else + prec = -1; + + if (*format == 'l' && format[1] == 'l') + { + size = 'L'; + format += 2; + } + else if (*format == 'h' || *format == 'l' || *format == 'L') + size = *format++; + + if (!*format) + break; + + type = *format++; + + switch (type) + { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, double)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + + case 'B' : /* Integer formats */ + case 'X' : + case 'b' : + case 'd' : + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, int)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + + case 'p' : /* Pointer value */ + if ((chars = va_arg(ap, int *)) != NULL) + *chars = bufptr - buffer; + break; + + case 'c' : /* Character or character array */ + if (width <= 1) + *bufptr++ = va_arg(ap, int); + else + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), width); + bufptr += width; + } + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) + s = "(null)"; + + slen = strlen(s); + if (slen > width && prec != width) + width = slen; + + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + if (slen > width) + slen = width; + + if (sign == '-') + { + strncpy(bufptr, s, slen); + memset(bufptr + slen, ' ', width - slen); + } + else + { + memset(bufptr, ' ', width - slen); + strncpy(bufptr + width - slen, s, slen); + } + + bufptr += width; + break; + + case 'n' : /* Output number of chars so far */ + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, int)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + } + } + else + *bufptr++ = *format++; + } + + /* + * Nul-terminate the string and return the number of characters in it. + */ + + *bufptr = '\0'; + return (bufptr - buffer); +} +#endif /* !HAVE_VSNPRINT */ + + +#ifndef HAVE_SNPRINTF +/* + * 'snprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +snprintf(char *buffer, /* O - Output buffer */ + size_t bufsize, /* O - Size of output buffer */ + const char *format, /* I - printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + int bytes; /* Number of bytes formatted */ + va_list ap; /* Pointer to additional arguments */ + + + va_start(ap, format); + bytes = vsnprintf(buffer, bufsize, format, ap); + va_end(ap); + + return (bytes); +} +#endif /* !HAVE_SNPRINTF */ + + +/* + * End of "$Id$". + */ + diff --git a/cups/string.c b/cups/string.c new file mode 100644 index 0000000000..46ed14cfb6 --- /dev/null +++ b/cups/string.c @@ -0,0 +1,125 @@ +/* + * "$Id$" + * + * String functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * strdup() - Duplicate a string. + * strcasecmp() - Do a case-insensitive comparison. + * strncasecmp() - Do a case-insensitive comparison on up to N chars. + */ + +/* + * Include necessary headers... + */ + +#include "string.h" + + +/* + * 'strdup()' - Duplicate a string. + */ + +# ifndef HAVE_STRDUP +char * /* O - New string pointer */ +strdup(const char *s) /* I - String to duplicate */ +{ + char *t; /* New string pointer */ + + + if (s == NULL) + return (NULL); + + if ((t = malloc(strlen(s) + 1)) == NULL) + return (NULL); + + return (strcpy(t, s)); +} +# endif /* !HAVE_STRDUP */ + + +/* + * 'strcasecmp()' - Do a case-insensitive comparison. + */ + +# ifndef HAVE_STRCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +strcasecmp(const char *s, /* I - First string */ + const char *t) /* I - Second string */ +{ + while (*s != '\0' && *t != '\0') + { + if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + + s ++; + t ++; + } + + if (*s == '\0' && *t == '\0') + return (0); + else if (*s != '\0') + return (1); + else + return (-1); +} +# endif /* !HAVE_STRCASECMP */ + +/* + * 'strncasecmp()' - Do a case-insensitive comparison on up to N chars. + */ + +# ifndef HAVE_STRNCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +strncasecmp(const char *s, /* I - First string */ + const char *t, /* I - Second string */ + size_t n) /* I - Maximum number of characters to compare */ +{ + while (*s != '\0' && *t != '\0' && n > 0) + { + if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + + s ++; + t ++; + n --; + } + + if (n == 0) + return (0); + else if (*s == '\0' && *t == '\0') + return (0); + else if (*s != '\0') + return (1); + else + return (-1); +} +# endif /* !HAVE_STRNCASECMP */ + + +/* + * End of "$Id$". + */ diff --git a/cups/string.h b/cups/string.h new file mode 100644 index 0000000000..0d144db0b4 --- /dev/null +++ b/cups/string.h @@ -0,0 +1,94 @@ +/* + * "$Id$" + * + * String definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_STRING_H_ +# define _CUPS_STRING_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# include + + +/* + * Stuff for WIN32 and OS/2... + */ + +# if defined(WIN32) || defined(__EMX__) +# define strcasecmp stricmp +# define strncasecmp strnicmp +# endif /* WIN32 || __EMX__ */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Prototypes... + */ + +# ifndef HAVE_STRDUP +extern char *strdup(const char *); +# endif /* !HAVE_STRDUP */ + +# ifndef HAVE_STRCASECMP +extern int strcasecmp(const char *, const char *); +# endif /* !HAVE_STRCASECMP */ + +# ifndef HAVE_STRNCASECMP +extern int strncasecmp(const char *, const char *, size_t n); +# endif /* !HAVE_STRNCASECMP */ + +# ifndef HAVE_SNPRINTF +extern int snprintf(char *, size_t, const char *, ...); +# endif /* !HAVE_SNPRINTF */ + +# ifndef HAVE_VSNPRINTF +extern int vsnprintf(char *, size_t, const char *, va_list); +# endif /* !HAVE_VSNPRINTF */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_STRING_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/tempfile.c b/cups/tempfile.c new file mode 100644 index 0000000000..1e0819da78 --- /dev/null +++ b/cups/tempfile.c @@ -0,0 +1,200 @@ +/* + * "$Id$" + * + * Temp file utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsTempFd() - Create a temporary file. + * cupsTempFile() - Generate a temporary filename. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" +#include "debug.h" +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cupsTempFd()' - Create a temporary file. + */ + +int /* O - New file descriptor */ +cupsTempFd(char *filename, /* I - Pointer to buffer */ + int len) /* I - Size of buffer */ +{ + int fd; /* File descriptor for temp file */ +#ifdef WIN32 + char tmpdir[1024]; /* Windows temporary directory */ + DWORD curtime; /* Current time */ +#else + char *tmpdir; /* TMPDIR environment var */ + struct timeval curtime; /* Current time */ +#endif /* WIN32 */ + static char buf[1024] = ""; /* Buffer if you pass in NULL and 0 */ + + + /* + * See if a filename was specified... + */ + + if (filename == NULL) + { + filename = buf; + len = sizeof(buf); + } + + /* + * See if TMPDIR is defined... + */ + +#ifdef WIN32 + GetTempPath(sizeof(tmpdir), tmpdir); +#else + if ((tmpdir = getenv("TMPDIR")) == NULL) + { + /* + * Put root temp files in restricted temp directory... + */ + + if (getuid() == 0) + tmpdir = CUPS_REQUESTS "/tmp"; + else + tmpdir = "/var/tmp"; + } +#endif /* WIN32 */ + + /* + * Make the temporary name using the specified directory... + */ + + do + { +#ifdef WIN32 + /* + * Get the current time of day... + */ + + curtime = GetTickCount(); + + /* + * Format a string using the hex time values... + */ + + snprintf(filename, len - 1, "%s/%08lx", tmpdir, curtime); +#else + /* + * Get the current time of day... + */ + + gettimeofday(&curtime, NULL); + + /* + * Format a string using the hex time values... + */ + + snprintf(filename, len - 1, "%s/%08lx%05lx", tmpdir, + curtime.tv_sec, curtime.tv_usec); +#endif /* WIN32 */ + + /* + * Open the file in "exclusive" mode, making sure that we don't + * stomp on an existing file or someone's symlink crack... + */ + +#ifdef O_NOFOLLOW + fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); +#else + fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); +#endif /* O_NOFOLLOW */ + + if (fd < 0 && errno == EPERM) + break; /* Stop immediately if permission denied! */ + } + while (fd < 0); + + /* + * Return the file descriptor... + */ + + return (fd); +} + + +/* + * 'cupsTempFile()' - Generate a temporary filename. + */ + +char * /* O - Filename */ +cupsTempFile(char *filename, /* I - Pointer to buffer */ + int len) /* I - Size of buffer */ +{ + int fd; /* File descriptor for temp file */ + static char buf[1024] = ""; /* Buffer if you pass in NULL and 0 */ + + + /* + * See if a filename was specified... + */ + + if (filename == NULL) + { + filename = buf; + len = sizeof(buf); + } + + /* + * Create the temporary file... + */ + + if ((fd = cupsTempFd(filename, len)) < 0) + return (NULL); + + /* + * Close the temp file - it'll be reopened later as needed... + */ + + close(fd); + + /* + * Return the temp filename... + */ + + return (filename); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testhttp.c b/cups/testhttp.c new file mode 100644 index 0000000000..76a15be544 --- /dev/null +++ b/cups/testhttp.c @@ -0,0 +1,124 @@ +/* + * "$Id$" + * + * HTTP test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include "http.h" + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* HTTP connection */ + http_status_t status; /* Status of GET command */ + char buffer[8192]; /* Input buffer */ + long bytes; /* Number of bytes read */ + FILE *out; /* Output file */ + char host[HTTP_MAX_URI], + method[HTTP_MAX_URI], + username[HTTP_MAX_URI], + resource[HTTP_MAX_URI]; + int port; + long length, total; + time_t start, current; + + + + http = NULL; + out = stdout; + + for (i = 1; i < argc; i ++) + { + if (strcmp(argv[i], "-o") == 0) + { + i ++; + out = fopen(argv[i], "wb"); + continue; + } + + httpSeparate(argv[i], method, username, host, &port, resource); + + http = httpConnect(host, port); + if (http == NULL) + { + perror(host); + continue; + } + printf("Requesting file \"%s\"...\n", resource); + httpClearFields(http); + httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + httpGet(http, resource); + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_OK) + puts("GET OK:"); + else + printf("GET failed with status %d...\n", status); + + + start = time(NULL); + length = atoi(httpGetField(http, HTTP_FIELD_CONTENT_LENGTH)); + total = 0; + + while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + { + total += bytes; + fwrite(buffer, bytes, 1, out); + if (out != stdout) + { + current = time(NULL); + if (current == start) current ++; + printf("\r%ld/%ld bytes (%ld bytes/sec) ", total, length, + total / (current - start)); + fflush(stdout); + } + } + } + + puts("Closing connection to server..."); + httpClose(http); + + if (out != stdout) + fclose(out); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testmime.dsp b/cups/testmime.dsp new file mode 100644 index 0000000000..33fbd301af --- /dev/null +++ b/cups/testmime.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="testmime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=testmime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testmime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testmime.mak" CFG="testmime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testmime - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "testmime - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testmime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 cups.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"testmime.exe" + +!ELSEIF "$(CFG)" == "testmime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "testmime___Win32_Debug" +# PROP BASE Intermediate_Dir "testmime___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../visualc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 cupsd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"testmimed.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "testmime - Win32 Release" +# Name "testmime - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\testmime.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mime.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/testppd.c b/cups/testppd.c new file mode 100644 index 0000000000..07602028f0 --- /dev/null +++ b/cups/testppd.c @@ -0,0 +1,198 @@ +/* + * "$Id$" + * + * PPD test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * main() - Main entry for test program. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" + + +/* + * 'main()' - Main entry for test program. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j, k, m; /* Looping vars */ + const char *filename; /* File to load */ + ppd_file_t *ppd; /* PPD file record */ + ppd_size_t *size; /* Size record */ + ppd_group_t *group; /* UI group */ + ppd_option_t *option; /* Standard UI option */ + ppd_choice_t *choice; /* Standard UI option choice */ + static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; + static char *sections[] = { "ANY", "DOCUMENT", "EXIT", + "JCL", "PAGE", "PROLOG" }; + + + /* + * Display PPD files for each file listed on the command-line... + */ + + if (argc == 1) + { + fputs("Usage: ppdtest filename1.ppd [... filenameN.ppd]\n", stderr); + return (1); + } + + for (i = 1; i < argc; i ++) + { + if (strstr(argv[i], ".ppd")) + filename = argv[i]; + else + filename = cupsGetPPD(argv[i]); + + if ((ppd = ppdOpenFile(filename)) == NULL) + { + fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename); + continue; + } + + printf("FILE: %s\n", filename); + printf(" language_level = %d\n", ppd->language_level); + printf(" color_device = %s\n", ppd->color_device ? "TRUE" : "FALSE"); + printf(" variable_sizes = %s\n", ppd->variable_sizes ? "TRUE" : "FALSE"); + printf(" landscape = %d\n", ppd->landscape); + + switch (ppd->colorspace) + { + case PPD_CS_CMYK : + puts(" colorspace = PPD_CS_CMYK"); + break; + case PPD_CS_CMY : + puts(" colorspace = PPD_CS_CMY"); + break; + case PPD_CS_GRAY : + puts(" colorspace = PPD_CS_GRAY"); + break; + case PPD_CS_RGB : + puts(" colorspace = PPD_CS_RGB"); + break; + default : + puts(" colorspace = "); + break; + } + + printf(" num_emulations = %d\n", ppd->num_emulations); + for (j = 0; j < ppd->num_emulations; j ++) + printf(" emulations[%d] = %s\n", j, ppd->emulations[j].name); + + printf(" lang_encoding = %s\n", ppd->lang_encoding); + printf(" lang_version = %s\n", ppd->lang_version); + printf(" modelname = %s\n", ppd->modelname); + printf(" ttrasterizer = %s\n", + ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer); + printf(" manufacturer = %s\n", ppd->manufacturer); + printf(" product = %s\n", ppd->product); + printf(" nickname = %s\n", ppd->nickname); + printf(" shortnickname = %s\n", ppd->shortnickname); + printf(" patches = %d bytes\n", + ppd->patches == NULL ? 0 : strlen(ppd->patches)); + + printf(" num_groups = %d\n", ppd->num_groups); + for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) + { + printf(" group[%d] = %s\n", j, group->text); + + for (k = 0, option = group->options; k < group->num_options; k ++, option ++) + { + printf(" options[%d] = %s (%s) %s %s %.0f\n", k, + option->keyword, option->text, uis[option->ui], + sections[option->section], option->order); + + if (strcmp(option->keyword, "PageSize") == 0 || + strcmp(option->keyword, "PageRegion") == 0) + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + size = ppdPageSize(ppd, choice->choice); + + if (size == NULL) + printf(" %s (%s) = ERROR", choice->choice, choice->text); + else + printf(" %s (%s) = %.2fx%.2fin (%.1f,%.1f,%.1f,%.1f)", choice->choice, + choice->text, size->width / 72.0, size->length / 72.0, + size->left / 72.0, size->bottom / 72.0, + size->right / 72.0, size->top / 72.0); + + if (strcmp(option->defchoice, choice->choice) == 0) + puts(" *"); + else + putchar('\n'); + } + } + else + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + printf(" %s (%s)", choice->choice, choice->text); + + if (strcmp(option->defchoice, choice->choice) == 0) + puts(" *"); + else + putchar('\n'); + } + } + } + } + + printf(" num_profiles = %d\n", ppd->num_profiles); + for (j = 0; j < ppd->num_profiles; j ++) + printf(" profiles[%d] = %s/%s %.3f %.3f [ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n", + j, ppd->profiles[j].resolution, ppd->profiles[j].media_type, + ppd->profiles[j].gamma, ppd->profiles[j].density, + ppd->profiles[j].matrix[0][0], ppd->profiles[j].matrix[0][1], + ppd->profiles[j].matrix[0][2], ppd->profiles[j].matrix[1][0], + ppd->profiles[j].matrix[1][1], ppd->profiles[j].matrix[1][2], + ppd->profiles[j].matrix[2][0], ppd->profiles[j].matrix[2][1], + ppd->profiles[j].matrix[2][2]); + + printf(" num_fonts = %d\n", ppd->num_fonts); + for (j = 0; j < ppd->num_fonts; j ++) + printf(" fonts[%d] = %s\n", j, ppd->fonts[j]); + + ppdClose(ppd); + } + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testppd.dsp b/cups/testppd.dsp new file mode 100644 index 0000000000..27d4f035ce --- /dev/null +++ b/cups/testppd.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="testppd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=testppd - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testppd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testppd.mak" CFG="testppd - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testppd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "testppd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testppd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 cups.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"testppd.exe" + +!ELSEIF "$(CFG)" == "testppd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "testppd___Win32_Debug" +# PROP BASE Intermediate_Dir "testppd___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../visualc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 cupsd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"testppdd.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "testppd - Win32 Release" +# Name "testppd - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\testppd.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ppd.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/usersys.c b/cups/usersys.c new file mode 100644 index 0000000000..9b2b41fe94 --- /dev/null +++ b/cups/usersys.c @@ -0,0 +1,447 @@ +/* + * "$Id$" + * + * User, system, and password routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsEncryption() - Get the default encryption settings... + * cupsGetPassword() - Get a password from the user... + * cupsServer() - Return the hostname of the default server... + * cupsSetEncryption() - Set the encryption preference. + * cupsSetPasswordCB() - Set the password callback for CUPS. + * cupsSetServer() - Set the default server name... + * cupsSetUser() - Set the default user name... + * cupsUser() - Return the current users name. + * cups_get_password() - Get a password from the user... + * cups_get_line() - Get a line from a file... + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" +#include +#include + + +/* + * Local functions... + */ + +static const char *cups_get_password(const char *prompt); +static char *cups_get_line(char *buf, int buflen, FILE *fp); + + +/* + * Local globals... + */ + +static http_encryption_t cups_encryption = (http_encryption_t)-1; +static char cups_user[65] = "", + cups_server[256] = ""; +static const char *(*cups_pwdcb)(const char *) = cups_get_password; + + +/* + * 'cupsEncryption()' - Get the default encryption settings... + */ + +http_encryption_t +cupsEncryption(void) +{ + FILE *fp; /* client.conf file */ + char *encryption; /* CUPS_ENCRYPTION variable */ + const char *home; /* Home directory of user */ + static char line[1024]; /* Line from file */ + + + /* + * First see if we have already set the encryption stuff... + */ + + if (cups_encryption == (http_encryption_t)-1) + { + /* + * Then see if the CUPS_ENCRYPTION environment variable is set... + */ + + if ((encryption = getenv("CUPS_ENCRYPTION")) == NULL) + { + /* + * Next check to see if we have a $HOME/.cupsrc or client.conf file... + */ + + if ((home = getenv("HOME")) != NULL) + { + snprintf(line, sizeof(line), "%s/.cupsrc", home); + fp = fopen(line, "r"); + } + else + fp = NULL; + + if (fp == NULL) + { + if ((home = getenv("CUPS_SERVERROOT")) != NULL) + { + snprintf(line, sizeof(line), "%s/client.conf", home); + fp = fopen(line, "r"); + } + else + fp = fopen(CUPS_SERVERROOT "/client.conf", "r"); + } + + encryption = "IfRequested"; + + if (fp != NULL) + { + /* + * Read the config file and look for a ServerName line... + */ + + while (cups_get_line(line, sizeof(line), fp) != NULL) + if (strncmp(line, "Encryption ", 11) == 0) + { + /* + * Got it! Drop any trailing newline and find the name... + */ + + encryption = line + strlen(line) - 1; + if (*encryption == '\n') + *encryption = '\0'; + + for (encryption = line + 11; isspace(*encryption); encryption ++); + break; + } + + fclose(fp); + } + } + + /* + * Set the encryption preference... + */ + + if (strcasecmp(encryption, "never") == 0) + cups_encryption = HTTP_ENCRYPT_NEVER; + else if (strcasecmp(encryption, "always") == 0) + cups_encryption = HTTP_ENCRYPT_ALWAYS; + else if (strcasecmp(encryption, "required") == 0) + cups_encryption = HTTP_ENCRYPT_REQUIRED; + else + cups_encryption = HTTP_ENCRYPT_IF_REQUESTED; + } + + return (cups_encryption); +} + + +/* + * 'cupsGetPassword()' - Get a password from the user... + */ + +const char * /* O - Password */ +cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return ((*cups_pwdcb)(prompt)); +} + + +/* + * 'cupsSetEncryption()' - Set the encryption preference. + */ + +void +cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */ +{ + cups_encryption = e; +} + + +/* + * 'cupsServer()' - Return the hostname of the default server... + */ + +const char * /* O - Server name */ +cupsServer(void) +{ + FILE *fp; /* client.conf file */ + char *server; /* Pointer to server name */ + const char *home; /* Home directory of user */ + static char line[1024]; /* Line from file */ + + + /* + * First see if we have already set the server name... + */ + + if (!cups_server[0]) + { + /* + * Then see if the CUPS_SERVER environment variable is set... + */ + + if ((server = getenv("CUPS_SERVER")) == NULL) + { + /* + * Next check to see if we have a $HOME/.cupsrc or client.conf file... + */ + + if ((home = getenv("HOME")) != NULL) + { + snprintf(line, sizeof(line), "%s/.cupsrc", home); + fp = fopen(line, "r"); + } + else + fp = NULL; + + if (fp == NULL) + { + if ((home = getenv("CUPS_SERVERROOT")) != NULL) + { + snprintf(line, sizeof(line), "%s/client.conf", home); + fp = fopen(line, "r"); + } + else + fp = fopen(CUPS_SERVERROOT "/client.conf", "r"); + } + + server = "localhost"; + + if (fp != NULL) + { + /* + * Read the config file and look for a ServerName line... + */ + + while (cups_get_line(line, sizeof(line), fp) != NULL) + if (strncmp(line, "ServerName ", 11) == 0) + { + /* + * Got it! Drop any trailing newline and find the name... + */ + + server = line + strlen(line) - 1; + if (*server == '\n') + *server = '\0'; + + for (server = line + 11; isspace(*server); server ++); + break; + } + + fclose(fp); + } + } + + /* + * Copy the server name over... + */ + + strncpy(cups_server, server, sizeof(cups_server) - 1); + cups_server[sizeof(cups_server) - 1] = '\0'; + } + + return (cups_server); +} + + +/* + * 'cupsSetPasswordCB()' - Set the password callback for CUPS. + */ + +void +cupsSetPasswordCB(const char *(*cb)(const char *)) /* I - Callback function */ +{ + if (cb == (const char *(*)(const char *))0) + cups_pwdcb = cups_get_password; + else + cups_pwdcb = cb; +} + + +/* + * 'cupsSetServer()' - Set the default server name... + */ + +void +cupsSetServer(const char *server) /* I - Server name */ +{ + if (server) + { + strncpy(cups_server, server, sizeof(cups_server) - 1); + cups_server[sizeof(cups_server) - 1] = '\0'; + } + else + cups_server[0] = '\0'; +} + + +/* + * 'cupsSetUser()' - Set the default user name... + */ + +void +cupsSetUser(const char *user) /* I - User name */ +{ + if (user) + { + strncpy(cups_user, user, sizeof(cups_user) - 1); + cups_user[sizeof(cups_user) - 1] = '\0'; + } + else + cups_user[0] = '\0'; +} + + +#if defined(WIN32) || defined(__EMX__) +/* + * WIN32 and OS/2 username and password stuff... + */ + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + if (!cups_user[0]) + strcpy(cups_user, "WindowsUser"); + + return (cups_user); +} + + +/* + * 'cups_get_password()' - Get a password from the user... + */ + +static const char * /* O - Password */ +cups_get_password(const char *prompt) /* I - Prompt string */ +{ + return (NULL); +} +#else +/* + * UNIX username and password stuff... + */ + +# include + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + struct passwd *pwd; /* User/password entry */ + + + if (!cups_user[0]) + { + /* + * Rewind the password file... + */ + + setpwent(); + + /* + * Lookup the password entry for the current user. + */ + + if ((pwd = getpwuid(getuid())) == NULL) + strcpy(cups_user, "unknown"); /* Unknown user! */ + else + { + /* + * Copy the username... + */ + + setpwent(); + + strncpy(cups_user, pwd->pw_name, sizeof(cups_user) - 1); + cups_user[sizeof(cups_user) - 1] = '\0'; + } + + /* + * Rewind the password file again... + */ + + setpwent(); + } + + return (cups_user); +} + + +/* + * 'cups_get_password()' - Get a password from the user... + */ + +static const char * /* O - Password */ +cups_get_password(const char *prompt) /* I - Prompt string */ +{ + return (getpass(prompt)); +} +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cups_get_line()' - Get a line from a file. + */ + +static char * /* O - Line from file */ +cups_get_line(char *buf, /* I - Line buffer */ + int buflen, /* I - Size of line buffer */ + FILE *fp) /* I - File to read from */ +{ + char *bufptr; /* Pointer to end of buffer */ + + + /* + * Get the line from a file... + */ + + if (fgets(buf, buflen, fp) == NULL) + return (NULL); + + /* + * Remove all trailing whitespace... + */ + + bufptr = buf + strlen(buf) - 1; + if (bufptr < buf) + return (NULL); + + while (isspace(*bufptr) && bufptr >= buf) + *bufptr-- = '\0'; + + return (buf); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/util.c b/cups/util.c new file mode 100644 index 0000000000..93071ef44b --- /dev/null +++ b/cups/util.c @@ -0,0 +1,1680 @@ +/* + * "$Id$" + * + * Printing utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2001 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsCancelJob() - Cancel a print job. + * cupsDoFileRequest() - Do an IPP request... + * cupsFreeJobs() - Free memory used by job data. + * cupsGetClasses() - Get a list of printer classes. + * cupsGetDefault() - Get the default printer or class. + * cupsGetJobs() - Get the jobs from the server. + * cupsGetPPD() - Get the PPD file for a printer. + * cupsGetPrinters() - Get a list of printers. + * cupsLastError() - Return the last IPP error that occurred. + * cupsPrintFile() - Print a file to a printer or class. + * cupsPrintFiles() - Print one or more files to a printer or class. + * cups_connect() - Connect to the specified host... + * cups_local_auth() - Get the local authorization certificate if + * available/applicable... + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "ipp.h" +#include "language.h" +#include "string.h" +#include "debug.h" +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local globals... + */ + +static http_t *cups_server = NULL; /* Current server connection */ +static ipp_status_t last_error = IPP_OK; /* Last IPP error */ +static char authstring[1024] = ""; /* Authorization string */ + + +/* + * Local functions... + */ + +static char *cups_connect(const char *name, char *printer, char *hostname); +static int cups_local_auth(http_t *http); + + +/* + * 'cupsCancelJob()' - Cancel a print job. + */ + +int /* O - 1 on success, 0 on failure */ +cupsCancelJob(const char *name, /* I - Name of printer or class */ + int job) /* I - Job ID */ +{ + char printer[HTTP_MAX_URI], /* Printer name */ + hostname[HTTP_MAX_URI], /* Hostname */ + uri[HTTP_MAX_URI]; /* Printer URI */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + cups_lang_t *language; /* Language info */ + + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + /* + * Build an IPP_CANCEL_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * job-id + * [requesting-user-name] + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_CANCEL_JOB; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request... + */ + + if ((response = cupsDoRequest(cups_server, request, "/jobs/")) == NULL) + { + last_error = IPP_BAD_REQUEST; + return (0); + } + else + { + last_error = response->request.status.status_code; + ippDelete(response); + + return (1); + } +} + + +/* + * 'cupsDoFileRequest()' - Do an IPP request... + */ + +ipp_t * /* O - Response data */ +cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ + ipp_t *request, /* I - IPP request */ + const char *resource, /* I - HTTP resource for POST */ + const char *filename) /* I - File to send or NULL */ +{ + ipp_t *response; /* IPP response data */ + char length[255]; /* Content-Length field */ + http_status_t status; /* Status of HTTP request */ + FILE *file; /* File to send */ + struct stat fileinfo; /* File information */ + int bytes; /* Number of bytes read/written */ + char buffer[8192]; /* Output buffer */ + const char *password; /* Password string */ + char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ + nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ + plain[255], /* Plaintext username:password */ + encode[512]; /* Encoded username:password */ + char prompt[1024]; /* Prompt string */ + + + if (http == NULL || request == NULL || resource == NULL) + { + if (request != NULL) + ippDelete(request); + + last_error = IPP_INTERNAL_ERROR; + return (NULL); + } + + DEBUG_printf(("cupsDoFileRequest(%p, %08x, \'%s\', \'%s\')\n", + http, request, resource, filename ? filename : "(null)")); + + /* + * See if we have a file to send... + */ + + if (filename != NULL) + { + if (stat(filename, &fileinfo)) + { + /* + * Can't get file information! + */ + + ippDelete(request); + last_error = IPP_NOT_FOUND; + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + ippDelete(request); + last_error = IPP_NOT_FOUND; + return (NULL); + } + } + else + file = NULL; + + /* + * Loop until we can send the request without authorization problems. + */ + + response = NULL; + status = HTTP_ERROR; + + while (response == NULL) + { + DEBUG_puts("cupsDoFileRequest: setup..."); + + /* + * Setup the HTTP variables needed... + */ + + if (filename != NULL) + sprintf(length, "%u", ippLength(request) + (size_t)fileinfo.st_size); + else + sprintf(length, "%u", ippLength(request)); + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, authstring); + + /* + * Try the request... + */ + + DEBUG_puts("cupsDoFileRequest: post..."); + + if (httpPost(http, resource)) + { + if (httpReconnect(http)) + { + status = HTTP_ERROR; + break; + } + else + continue; + } + + /* + * Send the IPP data and wait for the response... + */ + + DEBUG_puts("cupsDoFileRequest: ipp write..."); + + request->state = IPP_IDLE; + if (ippWrite(http, request) != IPP_ERROR) + if (filename != NULL) + { + DEBUG_puts("cupsDoFileRequest: file write..."); + + /* + * Send the file... + */ + + rewind(file); + + while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) + if (httpWrite(http, buffer, bytes) < bytes) + break; + } + + /* + * Get the server's return status... + */ + + DEBUG_puts("cupsDoFileRequest: update..."); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + DEBUG_puts("cupsDoFileRequest: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(http)) + continue; + + /* + * Nope - get a password from the user... + */ + + snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), + http->hostname); + + if ((password = cupsGetPassword(prompt)) != NULL) + { + /* + * Got a password; send it to the server... + */ + + if (!password[0]) + break; + + if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0) + { + /* + * Basic authentication... + */ + + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); + httpEncode64(encode, plain); + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + } + else + { + /* + * Digest authentication... + */ + + httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); + httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); + + httpMD5(cupsUser(), realm, password, encode); + httpMD5Final(nonce, "POST", resource, encode); + snprintf(authstring, sizeof(authstring), + "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " + "response=\"%s\"", cupsUser(), realm, nonce, encode); + } + continue; + } + else + break; + } + else if (status == HTTP_ERROR) + { +#if defined(WIN32) || defined(__EMX__) + if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH) +#else + if (http->error != ENETDOWN && http->error != ENETUNREACH) +#endif /* WIN32 || __EMX__ */ + continue; + else + break; + } +#ifdef HAVE_LIBSSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * Try again, this time with encryption enabled... + */ + + continue; + } +#endif /* HAVE_LIBSSL */ + else if (status != HTTP_OK) + { + DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); + + /* + * Flush any error message... + */ + + httpFlush(http); + break; + } + else + { + /* + * Read the response... + */ + + DEBUG_puts("cupsDoFileRequest: response..."); + + response = ippNew(); + + if (ippRead(http, response) == IPP_ERROR) + { + /* + * Delete the response... + */ + + ippDelete(response); + response = NULL; + + last_error = IPP_SERVICE_UNAVAILABLE; + break; + } + } + } + + /* + * Close the file if needed... + */ + + if (filename != NULL) + fclose(file); + + /* + * Flush any remaining data... + */ + + httpFlush(http); + + /* + * Delete the original request and return the response... + */ + + ippDelete(request); + + if (response) + last_error = response->request.status.status_code; + else if (status == HTTP_NOT_FOUND) + last_error = IPP_NOT_FOUND; + else if (status == HTTP_UNAUTHORIZED) + last_error = IPP_NOT_AUTHORIZED; + else if (status != HTTP_OK) + last_error = IPP_SERVICE_UNAVAILABLE; + + return (response); +} + + +/* + * 'cupsFreeJobs()' - Free memory used by job data. + */ + +void +cupsFreeJobs(int num_jobs,/* I - Number of jobs */ + cups_job_t *jobs) /* I - Jobs */ +{ + int i; /* Looping var */ + + + if (num_jobs <= 0 || jobs == NULL) + return; + + for (i = 0; i < num_jobs; i ++) + { + free(jobs[i].dest); + free(jobs[i].user); + free(jobs[i].format); + free(jobs[i].title); + } + + free(jobs); +} + + +/* + * 'cupsGetClasses()' - Get a list of printer classes. + */ + +int /* O - Number of classes */ +cupsGetClasses(char ***classes) /* O - Classes */ +{ + int n; /* Number of classes */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + char **temp; /* Temporary pointer */ + + + if (classes == NULL) + { + last_error = IPP_INTERNAL_ERROR; + return (0); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + /* + * Build a CUPS_GET_CLASSES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * requested-attributes + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_CLASSES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "printer-name"); + + /* + * Do the request and get back a response... + */ + + n = 0; + *classes = NULL; + + if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) + { + last_error = response->request.status.status_code; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (attr->name != NULL && + strcasecmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + temp = malloc(sizeof(char *)); + else + temp = realloc(*classes, sizeof(char *) * (n + 1)); + + if (temp == NULL) + { + /* + * Ran out of memory! + */ + + while (n > 0) + { + n --; + free((*classes)[n]); + } + + free(*classes); + ippDelete(response); + return (0); + } + + *classes = temp; + temp[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (n); +} + + +/* + * 'cupsGetDefault()' - Get the default printer or class. + */ + +const char * /* O - Default printer or NULL */ +cupsGetDefault(void) +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + const char *var; /* Environment variable */ + static char def_printer[256];/* Default printer */ + + + /* + * First see if the LPDEST or PRINTER environment variables are + * set... However, if PRINTER is set to "lp", ignore it to work + * around a "feature" in most Linux distributions - the default + * user login scripts set PRINTER to "lp"... + */ + + if ((var = getenv("LPDEST")) != NULL) + return (var); + else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) + return (var); + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + + /* + * Build a CUPS_GET_DEFAULT request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_DEFAULT; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) + { + last_error = response->request.status.status_code; + + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + { + strncpy(def_printer, attr->values[0].string.text, sizeof(def_printer) - 1); + def_printer[sizeof(def_printer) - 1] = '\0'; + ippDelete(response); + return (def_printer); + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (NULL); +} + + +/* + * 'cupsGetJobs()' - Get the jobs from the server. + */ + +int /* O - Number of jobs */ +cupsGetJobs(cups_job_t **jobs, /* O - Job data */ + const char *mydest, /* I - Only show jobs for dest? */ + int myjobs, /* I - Only show my jobs? */ + int completed) /* I - Only show completed jobs? */ +{ + int n; /* Number of jobs */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + cups_job_t *temp; /* Temporary pointer */ + int id, /* job-id */ + priority, /* job-priority */ + size; /* job-k-octets */ + ipp_jstate_t state; /* job-state */ + time_t completed_time, /* time-at-completed */ + creation_time, /* time-at-creation */ + processing_time; /* time-at-processing */ + const char *dest, /* job-printer-uri */ + *format, /* document-format */ + *title, /* job-name */ + *user; /* job-originating-user-name */ + char uri[HTTP_MAX_URI]; /* URI for jobs */ + static const char *attrs[] = /* Requested attributes */ + { + "job-id", + "job-priority", + "job-k-octets", + "job-state", + "time-at-completed", + "time-at-creation", + "time-at-processing", + "job-printer-uri", + "document-format", + "job-name", + "job-originating-user-name" + }; + + + if (jobs == NULL) + { + last_error = IPP_INTERNAL_ERROR; + return (0); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + * which-jobs + * my-jobs + * requested-attributes + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (mydest) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", mydest); + else + strcpy(uri, "ipp://localhost/jobs"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser()); + + if (myjobs) + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + + if (completed) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "which-jobs", NULL, "completed"); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), + NULL, attrs); + + /* + * Do the request and get back a response... + */ + + n = 0; + *jobs = NULL; + + if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) + { + last_error = response->request.status.status_code; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + id = 0; + size = 0; + priority = 50; + state = IPP_JOB_PENDING; + user = NULL; + dest = NULL; + format = NULL; + title = NULL; + creation_time = 0; + completed_time = 0; + processing_time = 0; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + id = attr->values[0].integer; + else if (strcmp(attr->name, "job-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + state = (ipp_jstate_t)attr->values[0].integer; + else if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + priority = attr->values[0].integer; + else if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + size = attr->values[0].integer; + else if (strcmp(attr->name, "time-at-completed") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + completed_time = attr->values[0].integer; + else if (strcmp(attr->name, "time-at-creation") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + creation_time = attr->values[0].integer; + else if (strcmp(attr->name, "time-at-processing") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + processing_time = attr->values[0].integer; + else if (strcmp(attr->name, "job-printer-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + { + if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) + dest ++; + } + else if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + user = attr->values[0].string.text; + else if (strcmp(attr->name, "document-format") == 0 && + attr->value_tag == IPP_TAG_MIMETYPE) + format = attr->values[0].string.text; + else if (strcmp(attr->name, "job-name") == 0 && + attr->value_tag == IPP_TAG_TEXT) + title = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (dest == NULL || format == NULL || title == NULL || user == NULL || + id == 0) + { + if (attr == NULL) + break; + else + continue; + } + + /* + * Allocate memory for the job... + */ + + if (n == 0) + temp = malloc(sizeof(cups_job_t)); + else + temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1)); + + if (temp == NULL) + { + /* + * Ran out of memory! + */ + + cupsFreeJobs(n, *jobs); + *jobs = NULL; + + ippDelete(response); + return (0); + } + + *jobs = temp; + temp += n; + n ++; + + /* + * Copy the data over... + */ + + temp->dest = strdup(dest); + temp->user = strdup(user); + temp->format = strdup(format); + temp->title = strdup(title); + temp->id = id; + temp->priority = priority; + temp->state = state; + temp->size = size; + temp->completed_time = completed_time; + temp->creation_time = creation_time; + temp->processing_time = processing_time; + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (n); +} + + +/* + * 'cupsGetPPD()' - Get the PPD file for a printer. + */ + +const char * /* O - Filename for PPD file */ +cupsGetPPD(const char *name) /* I - Printer name */ +{ + int i; /* Looping var */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Local language */ + int fd; /* PPD file */ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + char printer[HTTP_MAX_URI], /* Printer name */ + method[HTTP_MAX_URI], /* Method/scheme name */ + username[HTTP_MAX_URI], /* Username:password */ + hostname[HTTP_MAX_URI], /* Hostname */ + resource[HTTP_MAX_URI]; /* Resource name */ + int port; /* Port number */ + const char *password; /* Password string */ + char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ + nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ + plain[255], /* Plaintext username:password */ + encode[512]; /* Encoded username:password */ + http_status_t status; /* HTTP status from server */ + char prompt[1024]; /* Prompt string */ + static char filename[HTTP_MAX_URI]; /* Local filename */ + static const char *requested_attrs[] =/* Requested attributes */ + { + "printer-uri-supported", + "printer-type", + "member-uris" + }; + + + if (name == NULL) + { + last_error = IPP_INTERNAL_ERROR; + return (NULL); + } + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requested-attributes + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + snprintf(buffer, sizeof(buffer), "ipp://localhost/printers/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, buffer); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", + sizeof(requested_attrs) / sizeof(requested_attrs[0]), + NULL, requested_attrs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) + { + last_error = response->request.status.status_code; + printer[0] = '\0'; + hostname[0] = '\0'; + + if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) + { + /* + * Get the first actual server and printer name in the class... + */ + + for (i = 0; i < attr->num_values; i ++) + { + httpSeparate(attr->values[0].string.text, method, username, hostname, + &port, resource); + if (strncmp(resource, "/printers/", 10) == 0) + { + /* + * Found a printer! + */ + + strncpy(printer, resource + 10, sizeof(printer) - 1); + printer[sizeof(printer) - 1] = '\0'; + break; + } + } + } + else if ((attr = ippFindAttribute(response, "printer-uri-supported", + IPP_TAG_URI)) != NULL) + { + /* + * Get the actual server and printer names... + */ + + httpSeparate(attr->values[0].string.text, method, username, hostname, + &port, resource); + strncpy(printer, strrchr(resource, '/') + 1, sizeof(printer) - 1); + printer[sizeof(printer) - 1] = '\0'; + } + + ippDelete(response); + + /* + * Remap local hostname to localhost... + */ + + gethostname(buffer, sizeof(buffer)); + + if (strcasecmp(buffer, hostname) == 0) + strcpy(hostname, "localhost"); + } + + cupsLangFree(language); + + if (!printer[0]) + return (NULL); + + /* + * Reconnect to the correct server as needed... + */ + + if (strcasecmp(cups_server->hostname, hostname) != 0) + { + httpClose(cups_server); + + if ((cups_server = httpConnect(hostname, ippPort())) == NULL) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + } + + /* + * Get a temp file... + */ + + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) + { + /* + * Can't open file; close the server connection and return NULL... + */ + + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + return (NULL); + } + + /* + * And send a request to the HTTP server... + */ + + snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer); + + do + { + httpClearFields(cups_server); + httpSetField(cups_server, HTTP_FIELD_HOST, hostname); + httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring); + + if (httpGet(cups_server, resource)) + { + if (httpReconnect(cups_server)) + { + status = HTTP_ERROR; + break; + } + else + { + status = HTTP_UNAUTHORIZED; + continue; + } + } + + while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + DEBUG_puts("cupsGetPPD: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(cups_server)) + continue; + + /* + * Nope, get a password from the user... + */ + + snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), + cups_server->hostname); + + if ((password = cupsGetPassword(prompt)) != NULL) + { + /* + * Got a password; send it to the server... + */ + + if (!password[0]) + break; + + if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0) + { + /* + * Basic authentication... + */ + + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); + httpEncode64(encode, plain); + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + } + else + { + /* + * Digest authentication... + */ + + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); + + httpMD5(cupsUser(), realm, password, encode); + httpMD5Final(nonce, "GET", resource, encode); + snprintf(authstring, sizeof(authstring), + "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " + "response=\"%s\"", cupsUser(), realm, nonce, encode); + } + continue; + } + else + break; + } + } + while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); + + /* + * See if we actually got the file or an error... + */ + + if (status != HTTP_OK) + { + unlink(filename); + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + return (NULL); + } + + /* + * OK, we need to copy the file... + */ + + while ((bytes = httpRead(cups_server, buffer, sizeof(buffer))) > 0) + write(fd, buffer, bytes); + + close(fd); + + return (filename); +} + + +/* + * 'cupsGetPrinters()' - Get a list of printers. + */ + +int /* O - Number of printers */ +cupsGetPrinters(char ***printers) /* O - Printers */ +{ + int n; /* Number of printers */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + char **temp; /* Temporary pointer */ + + + if (printers == NULL) + { + last_error = IPP_INTERNAL_ERROR; + return (0); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * requested-attributes + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "printer-name"); + + /* + * Do the request and get back a response... + */ + + n = 0; + *printers = NULL; + + if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) + { + last_error = response->request.status.status_code; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (attr->name != NULL && + strcasecmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + temp = malloc(sizeof(char *)); + else + temp = realloc(*printers, sizeof(char *) * (n + 1)); + + if (temp == NULL) + { + /* + * Ran out of memory! + */ + + while (n > 0) + { + n --; + free((*printers)[n]); + } + + free(*printers); + ippDelete(response); + return (0); + } + + *printers = temp; + temp[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (n); +} + + +/* + * 'cupsLastError()' - Return the last IPP error that occurred. + */ + +ipp_status_t /* O - IPP error code */ +cupsLastError(void) +{ + return (last_error); +} + + +/* + * 'cupsPrintFile()' - Print a file to a printer or class. + */ + +int /* O - Job ID */ +cupsPrintFile(const char *name, /* I - Printer or class name */ + const char *filename, /* I - File to print */ + const char *title, /* I - Title of job */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %p)\n", + name, filename, num_options, options)); + + return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); +} + + +/* + * 'cupsPrintFiles()' - Print one or more files to a printer or class. + */ + +int /* O - Job ID */ +cupsPrintFiles(const char *name, /* I - Printer or class name */ + int num_files, /* I - Number of files */ + const char **files, /* I - File(s) to print */ + const char *title, /* I - Title of job */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + const char *val; /* Pointer to option value */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP job-id attribute */ + char hostname[HTTP_MAX_URI], /* Hostname */ + printer[HTTP_MAX_URI], /* Printer or class name */ + uri[HTTP_MAX_URI]; /* Printer URI */ + cups_lang_t *language; /* Language to use */ + int jobid; /* New job ID */ + + + DEBUG_printf(("cupsPrintFiles(\'%s\', %d, %p, %d, %p)\n", + name, num_files, files, num_options, options)); + + if (name == NULL || num_files < 1 || files == NULL) + return (0); + + /* + * Setup a connection and request data... + */ + + if (!cups_connect(name, printer, hostname)) + { + DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n", + strerror(errno))); + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + language = cupsLangDefault(); + + /* + * Build a standard CUPS URI for the printer and fill the standard IPP + * attributes... + */ + + if ((request = ippNew()) == NULL) + return (0); + + request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB : + IPP_CREATE_JOB; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + if (title) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); + + /* + * Then add all options... + */ + + cupsEncodeOptions(request, num_options, options); + + /* + * Do the request... + */ + + snprintf(uri, sizeof(uri), "/printers/%s", printer); + + if (num_files == 1) + response = cupsDoFileRequest(cups_server, request, uri, *files); + else + response = cupsDoRequest(cups_server, request, uri); + + if (response == NULL) + jobid = 0; + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + DEBUG_printf(("IPP response code was 0x%x!\n", + response->request.status.status_code)); + jobid = 0; + } + else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) + { + DEBUG_puts("No job ID!"); + jobid = 0; + } + else + jobid = attr->values[0].integer; + + if (response != NULL) + ippDelete(response); + + /* + * Handle multiple file jobs if the create-job operation worked... + */ + + if (jobid > 0 && num_files > 1) + for (i = 0; i < num_files; i ++) + { + /* + * Build a standard CUPS URI for the job and fill the standard IPP + * attributes... + */ + + if ((request = ippNew()) == NULL) + return (0); + + request->request.op.operation_id = IPP_SEND_DOCUMENT; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s:%d/jobs/%d", hostname, ippPort(), + jobid); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, uri); + + /* + * Handle raw print files... + */ + + if (cupsGetOption("raw", num_options, options)) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/vnd.cups-raw"); + else if ((val = cupsGetOption("document-format", num_options, options)) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, val); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/octet-stream"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Is this the last document? + */ + + if (i == (num_files - 1)) + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); + + /* + * Send the file... + */ + + snprintf(uri, sizeof(uri), "/printers/%s", printer); + + if ((response = cupsDoFileRequest(cups_server, request, uri, + files[i])) != NULL) + ippDelete(response); + } + + return (jobid); +} + + +/* + * 'cups_connect()' - Connect to the specified host... + */ + +static char * /* I - Printer name or NULL */ +cups_connect(const char *name, /* I - Destination (printer[@host]) */ + char *printer, /* O - Printer name [HTTP_MAX_URI] */ + char *hostname) /* O - Hostname [HTTP_MAX_URI] */ +{ + char hostbuf[HTTP_MAX_URI]; /* Name of host */ + static char printerbuf[HTTP_MAX_URI]; + /* Name of printer or class */ + + + DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); + + if (name == NULL) + { + last_error = IPP_BAD_REQUEST; + return (NULL); + } + + if (sscanf(name, "%1023[^@]@%1023s", printerbuf, hostbuf) == 1) + { + strncpy(hostbuf, cupsServer(), sizeof(hostbuf) - 1); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + } + + if (hostname != NULL) + { + strncpy(hostname, hostbuf, HTTP_MAX_URI - 1); + hostname[HTTP_MAX_URI - 1] = '\0'; + } + else + hostname = hostbuf; + + if (printer != NULL) + { + strncpy(printer, printerbuf, HTTP_MAX_URI - 1); + printer[HTTP_MAX_URI - 1] = '\0'; + } + else + printer = printerbuf; + + if (cups_server != NULL) + { + if (strcasecmp(cups_server->hostname, hostname) == 0) + return (printer); + + httpClose(cups_server); + } + + DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); + + if ((cups_server = httpConnect(hostname, ippPort())) == NULL) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + else + { + httpEncryption(cups_server, cupsEncryption()); + return (printer); + } +} + + +/* + * 'cups_local_auth()' - Get the local authorization certificate if + * available/applicable... + */ + +static int /* O - 1 if available, 0 if not */ +cups_local_auth(http_t *http) /* I - Connection */ +{ +#if defined(WIN32) || defined(__EMX__) + /* + * Currently WIN32 and OS-2 do not support the CUPS server... + */ + + return (0); +#else + int pid; /* Current process ID */ + FILE *fp; /* Certificate file */ + char filename[1024], /* Certificate filename */ + certificate[33];/* Certificate string */ + const char *root; /* Server root directory */ + + + /* + * See if we are accessing localhost... + */ + + if (ntohl(http->hostaddr.sin_addr.s_addr) != 0x7f000001 && + strcasecmp(http->hostname, "localhost") != 0) + return (0); + + /* + * Try opening a certificate file for this PID. If that fails, + * try the root certificate... + */ + + if ((root = getenv("CUPS_SERVERROOT")) == NULL) + root = CUPS_SERVERROOT; + + pid = getpid(); + snprintf(filename, sizeof(filename), "%s/certs/%d", root, pid); + if ((fp = fopen(filename, "r")) == NULL && pid > 0) + { + snprintf(filename, sizeof(filename), "%s/certs/0", root); + fp = fopen(filename, "r"); + } + + if (fp == NULL) + return (0); + + /* + * Read the certificate from the file... + */ + + fgets(certificate, sizeof(certificate), fp); + fclose(fp); + + /* + * Set the authorization string and return... + */ + + snprintf(authstring, sizeof(authstring), "Local %s", certificate); + + return (1); +#endif /* WIN32 || __EMX__ */ +} + + +/* + * End of "$Id$". + */ diff --git a/data/HPGLprolog b/data/HPGLprolog new file mode 100644 index 0000000000..7dd477d48c --- /dev/null +++ b/data/HPGLprolog @@ -0,0 +1,37 @@ +%%BeginResource: procset hpgltops 1.1 0 +% +% "$Id: HPGLprolog 1605 2001-03-02 22:34:21Z andy $" +% +% HP-GL/2 filter procset for the Common UNIX Printing System (CUPS). +% +% This procset contains the basic drawing commands that are used to +% reduce output size. Note the 'MP' (make newpath) definition - this +% should be called 'NP' (newpath), but GhostScript uses the 'NP' name +% for 'noaccess put' in some of its font files... +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/MO { moveto } bind def +/LI { lineto } bind def +/FI { fill } bind def +/ST { stroke } bind def +/CP { closepath } bind def +/MP { newpath } bind def +/SP { setlinewidth setrgbcolor } bind def +%%EndResource diff --git a/data/Makefile b/data/Makefile new file mode 100644 index 0000000000..a3e802af9e --- /dev/null +++ b/data/Makefile @@ -0,0 +1,107 @@ +# +# "$Id$" +# +# Datafile makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Data files... +# + +BANNERS = classified \ + confidential \ + secret \ + standard \ + topsecret \ + unclassified + +CHARSETS = windows-874 \ + windows-1250 \ + windows-1251 \ + windows-1252 \ + windows-1253 \ + windows-1254 \ + windows-1255 \ + windows-1256 \ + windows-1257 \ + windows-1258 \ + iso-8859-1 \ + iso-8859-2 \ + iso-8859-3 \ + iso-8859-4 \ + iso-8859-5 \ + iso-8859-6 \ + iso-8859-7 \ + iso-8859-8 \ + iso-8859-9 \ + iso-8859-10 \ + iso-8859-13 \ + iso-8859-14 \ + iso-8859-15 \ + utf-8 +DATAFILES = HPGLprolog psglyphs testprint.ps + + +# +# Make everything... +# + +all: + + +# +# Clean all config and object files... +# + +clean: + + +# +# Install files... +# + +install: + -$(MKDIR) $(DATADIR)/banners + $(CHMOD) ugo+rx $(DATADIR) + $(CHMOD) ugo+rx $(DATADIR)/banners + $(INSTALL_DATA) $(BANNERS) $(DATADIR)/banners + -$(MKDIR) $(DATADIR)/charsets + $(CHMOD) ugo+rx $(DATADIR)/charsets + $(INSTALL_DATA) $(CHARSETS) $(DATADIR)/charsets + -$(MKDIR) $(DATADIR)/data + $(CHMOD) ugo+rx $(DATADIR)/data + $(INSTALL_DATA) $(DATAFILES) $(DATADIR)/data + -if test "$(PAMDIR)" != ""; then \ + $(MKDIR) $(PAMDIR); \ + $(CHMOD) ugo+rx $(PAMDIR); \ + if test -f /lib/security/pam_unix.so; then \ + $(INSTALL_DATA) cups.suse $(PAMDIR)/cups; \ + else \ + $(INSTALL_DATA) cups.pam $(PAMDIR)/cups; \ + fi \ + fi + + +# +# End of "$Id$". +# diff --git a/data/classified b/data/classified new file mode 100644 index 0000000000..5e97c58ec4 --- /dev/null +++ b/data/classified @@ -0,0 +1,277 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the label at the top and bottom... + 0 setgray % Color + + pageWidth 36 mul % Center of page + pageHeight 72 mul % Top of page + pageWidth -7 mul add % - 2 lines + moveto % Position text + bigFont setfont % Font + (Classified) CENTER % Show text centered + + pageWidth 36 mul % Center of page + pageHeight 6 mul % Bottom of page + moveto % Position text + bigFont setfont % Font + (Classified) CENTER % Show text centered + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: classified 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/confidential b/data/confidential new file mode 100644 index 0000000000..9640beda85 --- /dev/null +++ b/data/confidential @@ -0,0 +1,277 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the label at the top and bottom... + 0 setgray % Color + + pageWidth 36 mul % Center of page + pageHeight 72 mul % Top of page + pageWidth -7 mul add % - 2 lines + moveto % Position text + bigFont setfont % Font + (Confidential) CENTER % Show text centered + + pageWidth 36 mul % Center of page + pageHeight 6 mul % Bottom of page + moveto % Position text + bigFont setfont % Font + (Confidential) CENTER % Show text centered + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: confidential 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/cups.pam b/data/cups.pam new file mode 100644 index 0000000000..f38e70184a --- /dev/null +++ b/data/cups.pam @@ -0,0 +1,2 @@ +auth required /lib/security/pam_pwdb.so nullok shadow +account required /lib/security/pam_pwdb.so diff --git a/data/cups.suse b/data/cups.suse new file mode 100644 index 0000000000..0c26fbe0d8 --- /dev/null +++ b/data/cups.suse @@ -0,0 +1,2 @@ +auth required /lib/security/pam_unix.so nullok shadow +account required /lib/security/pam_unix.so diff --git a/data/iso-8859-1 b/data/iso-8859-1 new file mode 100644 index 0000000000..057d8aee3d --- /dev/null +++ b/data/iso-8859-1 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-1 +# (Latin1/West European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/iso-8859-10 b/data/iso-8859-10 new file mode 100644 index 0000000000..31f55552ee --- /dev/null +++ b/data/iso-8859-10 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-10 +# (Latin6/Nordic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0104 +A2 0112 +A3 0122 +A4 012A +A5 0128 +A6 0136 +A7 00A7 +A8 013B +A9 0110 +AA 0160 +AB 0166 +AC 017D +AD 00AD +AE 016A +AF 014A +B0 00B0 +B1 0105 +B2 0113 +B3 0123 +B4 012B +B5 0129 +B6 0137 +B7 00B7 +B8 013C +B9 0111 +BA 0161 +BB 0167 +BC 017E +BD 2015 +BE 016B +BF 014B +C0 0100 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 012E +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 0116 +CD 00CD +CE 00CE +CF 00CF +D0 0110 +D1 0145 +D2 014C +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 0168 +D8 00D8 +D9 0172 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 0101 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 012F +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 0117 +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 0146 +F2 014D +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 0169 +F8 00F8 +F9 0173 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FD +FF 0138 diff --git a/data/iso-8859-13 b/data/iso-8859-13 new file mode 100644 index 0000000000..dcfacca9d3 --- /dev/null +++ b/data/iso-8859-13 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-13 +# (Latin7/Baltic Rim) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 201D +A2 00A2 +A3 00A3 +A4 00A4 +A5 201E +A6 00A6 +A7 00A7 +A8 00D8 +A9 00A9 +AA 0156 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00C6 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 201C +B5 00B5 +B6 00B6 +B7 00B7 +B8 00F8 +B9 00B9 +BA 0157 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00E6 +C0 0104 +C1 012E +C2 0100 +C3 0106 +C4 00C4 +C5 00C5 +C6 0118 +C7 0112 +C8 010C +C9 00C9 +CA 0179 +CB 0116 +CC 0122 +CD 0136 +CE 012A +CF 013B +D0 0160 +D1 0143 +D2 0145 +D3 00D3 +D4 014C +D5 00D5 +D6 00D6 +D7 00D7 +D8 0172 +D9 0141 +DA 015A +DB 016A +DC 00DC +DD 017B +DE 017D +DF 00DF +E0 0105 +E1 012F +E2 0101 +E3 0107 +E4 00E4 +E5 00E5 +E6 0119 +E7 0113 +E8 010D +E9 00E9 +EA 017A +EB 0117 +EC 0123 +ED 0137 +EE 012B +EF 013C +F0 0161 +F1 0144 +F2 0146 +F3 00F3 +F4 014D +F5 00F5 +F6 00F6 +F7 00F7 +F8 0173 +F9 0142 +FA 015B +FB 016B +FC 00FC +FD 017C +FE 017E +FF 2019 diff --git a/data/iso-8859-14 b/data/iso-8859-14 new file mode 100644 index 0000000000..ca0097a47d --- /dev/null +++ b/data/iso-8859-14 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-14 +# (Latin8/Celtic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 1E02 +A2 1E03 +A3 00A3 +A4 010A +A5 010B +A6 1E0A +A7 00A7 +A8 1E80 +A9 00A9 +AA 1E82 +AB 1E0B +AC 1EF2 +AD 00AD +AE 00AE +AF 0178 +B0 1E1E +B1 1E1F +B2 0120 +B3 0121 +B4 1E40 +B5 1E41 +B6 00B6 +B7 1E56 +B8 1E81 +B9 1E57 +BA 1E83 +BB 1E60 +BC 1EF3 +BD 1E84 +BE 1E85 +BF 1E61 +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 0174 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 1E6A +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 0176 +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 0175 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 1E6B +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 0177 +FF 00FF diff --git a/data/iso-8859-15 b/data/iso-8859-15 new file mode 100644 index 0000000000..334160f4f2 --- /dev/null +++ b/data/iso-8859-15 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-15 +# (Latin9/West Europe + Euro) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 20AC +A5 00A5 +A6 0160 +A7 00A7 +A8 0161 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 017D +B5 00B5 +B6 00B6 +B7 00B7 +B8 017E +B9 00B9 +BA 00BA +BB 00BB +BC 0152 +BD 0153 +BE 0178 +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/iso-8859-2 b/data/iso-8859-2 new file mode 100644 index 0000000000..19b77878d4 --- /dev/null +++ b/data/iso-8859-2 @@ -0,0 +1,253 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-2 +# (Latin2/East European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8A 0160 +8B 2039 +8C 015A +8D 0164 +8E 017D +8F 0179 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0161 +9B 203A +8C 015B +8D 0165 +8E 017E +8F 017A +A0 00A0 +A1 0104 +A2 02D8 +A3 0141 +A4 00A4 +A5 013D +A6 015A +A7 00A7 +A8 00A8 +A9 0160 +AA 015E +AB 0164 +AC 0179 +AD 00AD +AE 017D +AF 017B +B0 00B0 +B1 0105 +B2 02DB +B3 0142 +B4 00B4 +B5 013E +B6 015B +B7 02C7 +B8 00B8 +B9 0161 +BA 015F +BB 0165 +BC 017A +BD 02DD +BE 017E +BF 017C +C0 0154 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 0139 +C6 0106 +C7 00C7 +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 011A +CD 00CD +CE 00CE +CF 010E +D0 0110 +D1 0143 +D2 0147 +D3 00D3 +D4 00D4 +D5 0150 +D6 00D6 +D7 00D7 +D8 0158 +D9 016E +DA 00DA +DB 0170 +DC 00DC +DD 00DD +DE 0162 +DF 00DF +E0 0155 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 013A +E6 0107 +E7 00E7 +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 011B +ED 00ED +EE 00EE +EF 010F +F0 0111 +F1 0144 +F2 0148 +F3 00F3 +F4 00F4 +F5 0151 +F6 00F6 +F7 00F7 +F8 0159 +F9 016F +FA 00FA +FB 0171 +FC 00FC +FD 00FD +FE 0163 +FF 02D9 diff --git a/data/iso-8859-3 b/data/iso-8859-3 new file mode 100644 index 0000000000..efc4529ed0 --- /dev/null +++ b/data/iso-8859-3 @@ -0,0 +1,244 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-3 +# (Latin3/South European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0126 +A2 02D8 +A3 00A3 +A4 00A4 +A6 0124 +A7 00A7 +A8 00A8 +A9 0130 +AA 015E +AB 011E +AC 0134 +AD 00AD +AF 017B +B0 00B0 +B1 0127 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 0125 +B7 00B7 +B8 00B8 +B9 0131 +BA 015F +BB 011F +BC 0135 +BD 00BD +BF 017C +C0 00C0 +C1 00C1 +C2 00C2 +C4 00C4 +C5 010A +C6 0108 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 0120 +D6 00D6 +D7 00D7 +D8 011C +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 016C +DE 015C +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E4 00E4 +E5 010B +E6 0109 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 0121 +F6 00F6 +F7 00F7 +F8 011D +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 016D +FE 015D +FF 02D9 diff --git a/data/iso-8859-4 b/data/iso-8859-4 new file mode 100644 index 0000000000..5c93156eb5 --- /dev/null +++ b/data/iso-8859-4 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-4 +# (Latin4/North European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0104 +A2 0138 +A3 0156 +A4 00A4 +A5 0128 +A6 013B +A7 00A7 +A8 00A8 +A9 0160 +AA 0112 +AB 0122 +AC 0166 +AD 00AD +AE 017D +AF 00AF +B0 00B0 +B1 0105 +B2 02DB +B3 0157 +B4 00B4 +B5 0129 +B6 013C +B7 02C7 +B8 00B8 +B9 0161 +BA 0113 +BB 0123 +BC 0167 +BD 014A +BE 017E +BF 014B +C0 0100 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 012E +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 0116 +CD 00CD +CE 00CE +CF 012A +D0 0110 +D1 0145 +D2 014C +D3 0136 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 0172 +DA 00DA +DB 00DB +DC 00DC +DD 0168 +DE 016A +DF 00DF +E0 0101 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 012F +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 0117 +ED 00ED +EE 00EE +EF 012B +F0 0111 +F1 0146 +F2 014D +F3 0137 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 0173 +FA 00FA +FB 00FB +FC 00FC +FD 0169 +FE 016B +FF 02D9 diff --git a/data/iso-8859-5 b/data/iso-8859-5 new file mode 100644 index 0000000000..59ee84d57a --- /dev/null +++ b/data/iso-8859-5 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-5 +# (Cyrillic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0401 +A2 0402 +A3 0403 +A4 0404 +A5 0405 +A6 0406 +A7 0407 +A8 0408 +A9 0409 +AA 040A +AB 040B +AC 040C +AD 00AD +AE 040E +AF 040F +B0 0410 +B1 0411 +B2 0412 +B3 0413 +B4 0414 +B5 0415 +B6 0416 +B7 0417 +B8 0418 +B9 0419 +BA 041A +BB 041B +BC 041C +BD 041D +BE 041E +BF 041F +C0 0420 +C1 0421 +C2 0422 +C3 0423 +C4 0424 +C5 0425 +C6 0426 +C7 0427 +C8 0428 +C9 0429 +CA 042A +CB 042B +CC 042C +CD 042D +CE 042E +CF 042F +D0 0430 +D1 0431 +D2 0432 +D3 0433 +D4 0434 +D5 0435 +D6 0436 +D7 0437 +D8 0438 +D9 0439 +DA 043A +DB 043B +DC 043C +DD 043D +DE 043E +DF 043F +E0 0440 +E1 0441 +E2 0442 +E3 0443 +E4 0444 +E5 0445 +E6 0446 +E7 0447 +E8 0448 +E9 0449 +EA 044A +EB 044B +EC 044C +ED 044D +EE 044E +EF 044F +F0 2116 +F1 0451 +F2 0452 +F3 0453 +F4 0454 +F5 0455 +F6 0456 +F7 0457 +F8 0458 +F9 0459 +FA 045A +FB 045B +FC 045C +FD 00A7 +FE 045E +FF 045F diff --git a/data/iso-8859-6 b/data/iso-8859-6 new file mode 100644 index 0000000000..356fe72e3b --- /dev/null +++ b/data/iso-8859-6 @@ -0,0 +1,206 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-6 +# (Arabic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0660 +31 0661 +32 0662 +33 0663 +34 0664 +35 0665 +36 0666 +37 0667 +38 0668 +39 0669 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A4 00A4 +AC 060C +AD 00AD +BB 061B +BF 061F +C1 0621 +C2 0622 +C3 0623 +C4 0624 +C5 0625 +C6 0626 +C7 0627 +C8 0628 +C9 0629 +CA 062A +CB 062B +CC 062C +CD 062D +CE 062E +CF 062F +D0 0630 +D1 0631 +D2 0632 +D3 0633 +D4 0634 +D5 0635 +D6 0636 +D7 0637 +D8 0638 +D9 0639 +DA 063A +E0 0640 +E1 0641 +E2 0642 +E3 0643 +E4 0644 +E5 0645 +E6 0646 +E7 0647 +E8 0648 +E9 0649 +EA 064A +EB 064B +EC 064C +ED 064D +EE 064E +EF 064F +F0 0650 +F1 0651 +F2 0652 diff --git a/data/iso-8859-7 b/data/iso-8859-7 new file mode 100644 index 0000000000..57647841cf --- /dev/null +++ b/data/iso-8859-7 @@ -0,0 +1,246 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-7 +# (Greek) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 9f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic +a0 ff ltor single Symbol + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 02BD +A2 02BC +A3 00A3 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AB 00AB +AC 00AC +AD 00AD +AF 2015 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 0384 +B5 0385 +B6 0386 +B7 00B7 +B8 0388 +B9 0389 +BA 038A +BB 00BB +BC 038C +BD 00BD +BE 038E +BF 038F +C0 0390 +C1 0391 +C2 0392 +C3 0393 +C4 0394 +C5 0395 +C6 0396 +C7 0397 +C8 0398 +C9 0399 +CA 039A +CB 039B +CC 039C +CD 039D +CE 039E +CF 039F +D0 03A0 +D1 03A1 +D3 03A3 +D4 03A4 +D5 03A5 +D6 03A6 +D7 03A7 +D8 03A8 +D9 03A9 +DA 03AA +DB 03AB +DC 03AC +DD 03AD +DE 03AE +DF 03AF +E0 03B0 +E1 03B1 +E2 03B2 +E3 03B3 +E4 03B4 +E5 03B5 +E6 03B6 +E7 03B7 +E8 03B8 +E9 03B9 +EA 03BA +EB 03BB +EC 03BC +ED 03BD +EE 03BE +EF 03BF +F0 03C0 +F1 03C1 +F2 03C2 +F3 03C3 +F4 03C4 +F5 03C5 +F6 03C6 +F7 03C7 +F8 03C8 +F9 03C9 +FA 03CA +FB 03CB +FC 03CC +FD 03CD +FE 03CE diff --git a/data/iso-8859-8 b/data/iso-8859-8 new file mode 100644 index 0000000000..a64c598f13 --- /dev/null +++ b/data/iso-8859-8 @@ -0,0 +1,214 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-8 +# (Hebrew) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 7f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic +80 ff rtol single Courier-Hebrew + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00D7 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 203E +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00F7 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +DF 2017 +E0 05D0 +E1 05D1 +E2 05D2 +E3 05D3 +E4 05D4 +E5 05D5 +E6 05D6 +E7 05D7 +E8 05D8 +E9 05D9 +EA 05DA +EB 05DB +EC 05DC +ED 05DD +EE 05DE +EF 05DF +F0 05E0 +F1 05E1 +F2 05E2 +F3 05E3 +F4 05E4 +F5 05E5 +F6 05E6 +F7 05E7 +F8 05E8 +F9 05E9 +FA 05EA diff --git a/data/iso-8859-9 b/data/iso-8859-9 new file mode 100644 index 0000000000..83a661edc2 --- /dev/null +++ b/data/iso-8859-9 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-9 +# (Latin5/Turkish) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 011E +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 0130 +DE 015E +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 011F +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 0131 +FE 015F +FF 00FF diff --git a/data/psglyphs b/data/psglyphs new file mode 100644 index 0000000000..c4a902c66c --- /dev/null +++ b/data/psglyphs @@ -0,0 +1,1051 @@ +0020 space +0021 exclam +0022 quotedbl +0023 numbersign +0024 dollar +0025 percent +0026 ampersand +0027 quotesingle +0028 parenleft +0029 parenright +002a asterisk +002b plus +002c comma +002d minus +002e period +002f slash +0030 zero +0031 one +0032 two +0033 three +0034 four +0035 five +0036 six +0037 seven +0038 eight +0039 nine +003a colon +003b semicolon +003c less +003d equal +003e greater +003f question +0040 at +0041 A +0042 B +0043 C +0044 D +0045 E +0046 F +0047 G +0048 H +0049 I +004a J +004b K +004c L +004d M +004e N +004f O +0050 P +0051 Q +0052 R +0053 S +0054 T +0055 U +0056 V +0057 W +0058 X +0059 Y +005a Z +005b bracketleft +005c backslash +005d bracketright +005e asciicircum +005f underscore +0060 grave +0061 a +0062 b +0063 c +0064 d +0065 e +0066 f +0067 g +0068 h +0069 i +006a j +006b k +006c l +006d m +006e n +006f o +0070 p +0071 q +0072 r +0073 s +0074 t +0075 u +0076 v +0077 w +0078 x +0079 y +007a z +007b braceleft +007c bar +007d braceright +007e asciitilde +00a0 space +00a1 exclamdown +00a2 cent +00a3 sterling +00a4 currency +00a5 yen +00a6 brokenbar +00a7 section +00a8 dieresis +00a9 copyright +00aa ordfeminine +00ab guillemotleft +00ac logicalnot +00ad hyphen +00ae registered +00af macron +00b0 degree +00b1 plusminus +00b2 twosuperior +00b3 threesuperior +00b4 acute +00b5 mu +00b6 paragraph +00b7 periodcentered +00b8 cedilla +00b9 onesuperior +00ba ordmasculine +00bb guillemotright +00bc onequarter +00bd onehalf +00be threequarters +00bf questiondown +00c0 Agrave +00c1 Aacute +00c2 Acircumflex +00c3 Atilde +00c4 Adieresis +00c5 Aring +00c6 AE +00c7 Ccedilla +00c8 Egrave +00c9 Eacute +00ca Ecircumflex +00cb Edieresis +00cc Igrave +00cd Iacute +00ce Icircumflex +00cf Idieresis +00d0 Eth +00d1 Ntilde +00d2 Ograve +00d3 Oacute +00d4 Ocircumflex +00d5 Otilde +00d6 Odieresis +00d7 multiply +00d8 Oslash +00d9 Ugrave +00da Uacute +00db Ucircumflex +00dc Udieresis +00dd Yacute +00de Thorn +00df germandbls +00e0 agrave +00e1 aacute +00e2 acircumflex +00e3 atilde +00e4 adieresis +00e5 aring +00e6 ae +00e7 ccedilla +00e8 egrave +00e9 eacute +00ea ecircumflex +00eb edieresis +00ec igrave +00ed iacute +00ee icircumflex +00ef idieresis +00f0 eth +00f1 ntilde +00f2 ograve +00f3 oacute +00f4 ocircumflex +00f5 otilde +00f6 odieresis +00f7 divide +00f8 oslash +00f9 ugrave +00fa uacute +00fb ucircumflex +00fc udieresis +00fd yacute +00fe thorn +00ff ydieresis +0100 Amacron +0101 amacron +0102 Abreve +0103 abreve +0104 Aogonek +0105 aogonek +0106 Cacute +0107 cacute +0108 Ccircumflex +0109 ccircumflex +010a Cdotaccent +010b cdotaccent +010c Ccaron +010d ccaron +010e Dcaron +010f dcaron +0110 Dcroat +0111 dcroat +0112 Emacron +0113 emacron +0114 Ebreve +0115 ebreve +0116 Edotaccent +0117 edotaccent +0118 Eogonek +0119 eogonek +011a Ecaron +011b ecaron +011c Gcircumflex +011d gcircumflex +011e Gbreve +011f gbreve +0120 Gdotaccent +0121 gdotaccent +0122 Gcommaaccent +0123 gcommaaccent +0124 Hcircumflex +0125 hcircumflex +0126 Hbar +0127 hbar +0128 Itilde +0129 itilde +012a Imacron +012b imacron +012c Ibreve +012d ibreve +012e Iogonek +012f iogonek +0130 Idotaccent +0131 dotlessi +0132 IJ +0133 ij +0134 Jcircumflex +0135 jcircumflex +0136 Kcommaaccent +0137 kcommaaccent +0138 kgreenlandic +0139 Lacute +013a lacute +013b Lcommaaccent +013c lcommaaccent +013d Lcaron +013e lcaron +013f Ldot +0140 ldot +0141 Lslash +0142 lslash +0143 Nacute +0144 nacute +0145 Ncommaaccent +0146 ncommaaccent +0147 Ncaron +0148 ncaron +0149 napostrophe +014a Eng +014b eng +014c Omacron +014d omacron +014e Obreve +014f obreve +0150 Ohungarumlaut +0151 ohungarumlaut +0152 OE +0153 oe +0154 Racute +0155 racute +0156 Rcommaaccent +0157 rcommaaccent +0158 Rcaron +0159 rcaron +015a Sacute +015b sacute +015c Scircumflex +015d scircumflex +015e Scedilla +015f scedilla +0160 Scaron +0161 scaron +0162 Tcommaaccent +0163 tcommaaccent +0164 Tcaron +0165 tcaron +0166 Tbar +0167 tbar +0168 Utilde +0169 utilde +016a Umacron +016b umacron +016c Ubreve +016d ubreve +016e Uring +016f uring +0170 Uhungarumlaut +0171 uhungarumlaut +0172 Uogonek +0173 uogonek +0174 Wcircumflex +0175 wcircumflex +0176 Ycircumflex +0177 ycircumflex +0178 Ydieresis +0179 Zacute +017a zacute +017b Zdotaccent +017c zdotaccent +017d Zcaron +017e zcaron +017f longs +0192 florin +01a0 Ohorn +01a1 ohorn +01af Uhorn +01b0 uhorn +01e6 Gcaron +01e7 gcaron +01fa Aringacute +01fb aringacute +01fc AEacute +01fd aeacute +01fe Oslashacute +01ff oslashacute +0218 Scommaaccent +0219 scommaaccent +021a Tcommaaccent +021b tcommaaccent +02bc afii57929 +02bd afii64937 +02c6 circumflex +02c7 caron +02c9 macron +02d8 breve +02d9 dotaccent +02da ring +02db ogonek +02dc tilde +02dd hungarumlaut +0300 gravecomb +0301 acutecomb +0303 tildecomb +0309 hookabovecomb +0323 dotbelowcomb +0384 tonos +0385 dieresistonos +0386 Alphatonos +0387 anoteleia +0388 Epsilontonos +0389 Etatonos +038a Iotatonos +038c Omicrontonos +038e Upsilontonos +038f Omegatonos +0390 iotadieresistonos +0391 Alpha +0392 Beta +0393 Gamma +0394 Delta +0395 Epsilon +0396 Zeta +0397 Eta +0398 Theta +0399 Iota +039a Kappa +039b Lambda +039c Mu +039d Nu +039e Xi +039f Omicron +03a0 Pi +03a1 Rho +03a3 Sigma +03a4 Tau +03a5 Upsilon +03a6 Phi +03a7 Chi +03a8 Psi +03a9 Omega +03aa Iotadieresis +03ab Upsilondieresis +03ac alphatonos +03ad epsilontonos +03ae etatonos +03af iotatonos +03b0 upsilondieresistonos +03b1 alpha +03b2 beta +03b3 gamma +03b4 delta +03b5 epsilon +03b6 zeta +03b7 eta +03b8 theta +03b9 iota +03ba kappa +03bb lambda +03bc mu +03bd nu +03be xi +03bf omicron +03c0 pi +03c1 rho +03c2 sigma1 +03c3 sigma +03c4 tau +03c5 upsilon +03c6 phi +03c7 chi +03c8 psi +03c9 omega +03ca iotadieresis +03cb upsilondieresis +03cc omicrontonos +03cd upsilontonos +03ce omegatonos +03d1 theta1 +03d2 Upsilon1 +03d5 phi1 +03d6 omega1 +0401 afii10023 +0402 afii10051 +0403 afii10052 +0404 afii10053 +0405 afii10054 +0406 afii10055 +0407 afii10056 +0408 afii10057 +0409 afii10058 +040a afii10059 +040b afii10060 +040c afii10061 +040e afii10062 +040f afii10145 +0410 afii10017 +0411 afii10018 +0412 afii10019 +0413 afii10020 +0414 afii10021 +0415 afii10022 +0416 afii10024 +0417 afii10025 +0418 afii10026 +0419 afii10027 +041a afii10028 +041b afii10029 +041c afii10030 +041d afii10031 +041e afii10032 +041f afii10033 +0420 afii10034 +0421 afii10035 +0422 afii10036 +0423 afii10037 +0424 afii10038 +0425 afii10039 +0426 afii10040 +0427 afii10041 +0428 afii10042 +0429 afii10043 +042a afii10044 +042b afii10045 +042c afii10046 +042d afii10047 +042e afii10048 +042f afii10049 +0430 afii10065 +0431 afii10066 +0432 afii10067 +0433 afii10068 +0434 afii10069 +0435 afii10070 +0436 afii10072 +0437 afii10073 +0438 afii10074 +0439 afii10075 +043a afii10076 +043b afii10077 +043c afii10078 +043d afii10079 +043e afii10080 +043f afii10081 +0440 afii10082 +0441 afii10083 +0442 afii10084 +0443 afii10085 +0444 afii10086 +0445 afii10087 +0446 afii10088 +0447 afii10089 +0448 afii10090 +0449 afii10091 +044a afii10092 +044b afii10093 +044c afii10094 +044d afii10095 +044e afii10096 +044f afii10097 +0451 afii10071 +0452 afii10099 +0453 afii10100 +0454 afii10101 +0455 afii10102 +0456 afii10103 +0457 afii10104 +0458 afii10105 +0459 afii10106 +045a afii10107 +045b afii10108 +045c afii10109 +045e afii10110 +045f afii10193 +0462 afii10146 +0463 afii10194 +0472 afii10147 +0473 afii10195 +0474 afii10148 +0475 afii10196 +0490 afii10050 +0491 afii10098 +04d9 afii10846 +05b0 afii57799 +05b1 afii57801 +05b2 afii57800 +05b3 afii57802 +05b4 afii57793 +05b5 afii57794 +05b6 afii57795 +05b7 afii57798 +05b8 afii57797 +05b9 afii57806 +05bb afii57796 +05bc afii57807 +05bd afii57839 +05be afii57645 +05bf afii57841 +05c0 afii57842 +05c1 afii57804 +05c2 afii57803 +05c3 afii57658 +05d0 afii57664 +05d1 afii57665 +05d2 afii57666 +05d3 afii57667 +05d4 afii57668 +05d5 afii57669 +05d6 afii57670 +05d7 afii57671 +05d8 afii57672 +05d9 afii57673 +05da afii57674 +05db afii57675 +05dc afii57676 +05dd afii57677 +05de afii57678 +05df afii57679 +05e0 afii57680 +05e1 afii57681 +05e2 afii57682 +05e3 afii57683 +05e4 afii57684 +05e5 afii57685 +05e6 afii57686 +05e7 afii57687 +05e8 afii57688 +05e9 afii57689 +05ea afii57690 +05f0 afii57716 +05f1 afii57717 +05f2 afii57718 +060c afii57388 +061b afii57403 +061f afii57407 +0621 afii57409 +0622 afii57410 +0623 afii57411 +0624 afii57412 +0625 afii57413 +0626 afii57414 +0627 afii57415 +0628 afii57416 +0629 afii57417 +062a afii57418 +062b afii57419 +062c afii57420 +062d afii57421 +062e afii57422 +062f afii57423 +0630 afii57424 +0631 afii57425 +0632 afii57426 +0633 afii57427 +0634 afii57428 +0635 afii57429 +0636 afii57430 +0637 afii57431 +0638 afii57432 +0639 afii57433 +063a afii57434 +0640 afii57440 +0641 afii57441 +0642 afii57442 +0643 afii57443 +0644 afii57444 +0645 afii57445 +0646 afii57446 +0647 afii57470 +0648 afii57448 +0649 afii57449 +064a afii57450 +064b afii57451 +064c afii57452 +064d afii57453 +064e afii57454 +064f afii57455 +0650 afii57456 +0651 afii57457 +0652 afii57458 +0660 afii57392 +0661 afii57393 +0662 afii57394 +0663 afii57395 +0664 afii57396 +0665 afii57397 +0666 afii57398 +0667 afii57399 +0668 afii57400 +0669 afii57401 +066a afii57381 +066d afii63167 +0679 afii57511 +067e afii57506 +0686 afii57507 +0688 afii57512 +0691 afii57513 +0698 afii57508 +06a4 afii57505 +06af afii57509 +06ba afii57514 +06d2 afii57519 +06d5 afii57534 +1e80 Wgrave +1e81 wgrave +1e82 Wacute +1e83 wacute +1e84 Wdieresis +1e85 wdieresis +1ef2 Ygrave +1ef3 ygrave +200c afii61664 +200d afii301 +200e afii299 +200f afii300 +2012 figuredash +2013 endash +2014 emdash +2015 afii00208 +2017 underscoredbl +2018 quoteleft +2019 quoteright +201a quotesinglbase +201b quotereversed +201c quotedblleft +201d quotedblright +201e quotedblbase +2020 dagger +2021 daggerdbl +2022 bullet +2024 onedotenleader +2025 twodotenleader +2026 ellipsis +202c afii61573 +202d afii61574 +202e afii61575 +2030 perthousand +2032 minute +2033 second +2039 guilsinglleft +203a guilsinglright +203c exclamdbl +2044 fraction +2070 zerosuperior +2074 foursuperior +2075 fivesuperior +2076 sixsuperior +2077 sevensuperior +2078 eightsuperior +2079 ninesuperior +207d parenleftsuperior +207e parenrightsuperior +207f nsuperior +2080 zeroinferior +2081 oneinferior +2082 twoinferior +2083 threeinferior +2084 fourinferior +2085 fiveinferior +2086 sixinferior +2087 seveninferior +2088 eightinferior +2089 nineinferior +208d parenleftinferior +208e parenrightinferior +20a1 colonmonetary +20a3 franc +20a4 lira +20a7 peseta +20aa afii57636 +20ab dong +20ac Euro +2105 afii61248 +2111 Ifraktur +2113 afii61289 +2116 afii61352 +2118 weierstrass +211c Rfraktur +211e prescription +2122 trademark +2126 Omega +212e estimated +2135 aleph +2153 onethird +2154 twothirds +215b oneeighth +215c threeeighths +215d fiveeighths +215e seveneighths +2190 arrowleft +2191 arrowup +2192 arrowright +2193 arrowdown +2194 arrowboth +2195 arrowupdn +21a8 arrowupdnbse +21b5 carriagereturn +21d0 arrowdblleft +21d1 arrowdblup +21d2 arrowdblright +21d3 arrowdbldown +21d4 arrowdblboth +2200 universal +2202 partialdiff +2203 existential +2205 emptyset +2206 Delta +2207 gradient +2208 element +2209 notelement +220b suchthat +220f product +2211 summation +2212 minus +2215 fraction +2217 asteriskmath +2219 periodcentered +221a radical +221d proportional +221e infinity +221f orthogonal +2220 angle +2227 logicaland +2228 logicalor +2229 intersection +222a union +222b integral +2234 therefore +223c similar +2245 congruent +2248 approxequal +2260 notequal +2261 equivalence +2264 lessequal +2265 greaterequal +2282 propersubset +2283 propersuperset +2284 notsubset +2286 reflexsubset +2287 reflexsuperset +2295 circleplus +2297 circlemultiply +22a5 perpendicular +22c5 dotmath +2302 house +2310 revlogicalnot +2320 integraltp +2321 integralbt +2329 angleleft +232a angleright +2500 SF100000 +2502 SF110000 +250c SF010000 +2510 SF030000 +2514 SF020000 +2518 SF040000 +251c SF080000 +2524 SF090000 +252c SF060000 +2534 SF070000 +253c SF050000 +2550 SF430000 +2551 SF240000 +2552 SF510000 +2553 SF520000 +2554 SF390000 +2555 SF220000 +2556 SF210000 +2557 SF250000 +2558 SF500000 +2559 SF490000 +255a SF380000 +255b SF280000 +255c SF270000 +255d SF260000 +255e SF360000 +255f SF370000 +2560 SF420000 +2561 SF190000 +2562 SF200000 +2563 SF230000 +2564 SF470000 +2565 SF480000 +2566 SF410000 +2567 SF450000 +2568 SF460000 +2569 SF400000 +256a SF540000 +256b SF530000 +256c SF440000 +2580 upblock +2584 dnblock +2588 block +258c lfblock +2590 rtblock +2591 ltshade +2592 shade +2593 dkshade +25a0 filledbox +25a1 H22073 +25aa H18543 +25ab H18551 +25ac filledrect +25b2 triagup +25ba triagrt +25bc triagdn +25c4 triaglf +25ca lozenge +25cb circle +25cf H18533 +25d8 invbullet +25d9 invcircle +25e6 openbullet +263a smileface +263b invsmileface +263c sun +2640 female +2642 male +2660 spade +2663 club +2665 heart +2666 diamond +266a musicalnote +266b musicalnotedbl +f6be dotlessj +f6bf LL +f6c0 ll +f6c1 Scedilla +f6c2 scedilla +f6c3 commaaccent +f6c4 afii10063 +f6c5 afii10064 +f6c6 afii10192 +f6c7 afii10831 +f6c8 afii10832 +f6c9 Acute +f6ca Caron +f6cb Dieresis +f6cc DieresisAcute +f6cd DieresisGrave +f6ce Grave +f6cf Hungarumlaut +f6d0 Macron +f6d1 cyrBreve +f6d2 cyrFlex +f6d3 dblGrave +f6d4 cyrbreve +f6d5 cyrflex +f6d6 dblgrave +f6d7 dieresisacute +f6d8 dieresisgrave +f6d9 copyrightserif +f6da registerserif +f6db trademarkserif +f6dc onefitted +f6dd rupiah +f6de threequartersemdash +f6df centinferior +f6e0 centsuperior +f6e1 commainferior +f6e2 commasuperior +f6e3 dollarinferior +f6e4 dollarsuperior +f6e5 hypheninferior +f6e6 hyphensuperior +f6e7 periodinferior +f6e8 periodsuperior +f6e9 asuperior +f6ea bsuperior +f6eb dsuperior +f6ec esuperior +f6ed isuperior +f6ee lsuperior +f6ef msuperior +f6f0 osuperior +f6f1 rsuperior +f6f2 ssuperior +f6f3 tsuperior +f6f4 Brevesmall +f6f5 Caronsmall +f6f6 Circumflexsmall +f6f7 Dotaccentsmall +f6f8 Hungarumlautsmall +f6f9 Lslashsmall +f6fa OEsmall +f6fb Ogoneksmall +f6fc Ringsmall +f6fd Scaronsmall +f6fe Tildesmall +f6ff Zcaronsmall +f721 exclamsmall +f724 dollaroldstyle +f726 ampersandsmall +f730 zerooldstyle +f731 oneoldstyle +f732 twooldstyle +f733 threeoldstyle +f734 fouroldstyle +f735 fiveoldstyle +f736 sixoldstyle +f737 sevenoldstyle +f738 eightoldstyle +f739 nineoldstyle +f73f questionsmall +f760 Gravesmall +f761 Asmall +f762 Bsmall +f763 Csmall +f764 Dsmall +f765 Esmall +f766 Fsmall +f767 Gsmall +f768 Hsmall +f769 Ismall +f76a Jsmall +f76b Ksmall +f76c Lsmall +f76d Msmall +f76e Nsmall +f76f Osmall +f770 Psmall +f771 Qsmall +f772 Rsmall +f773 Ssmall +f774 Tsmall +f775 Usmall +f776 Vsmall +f777 Wsmall +f778 Xsmall +f779 Ysmall +f77a Zsmall +f7a1 exclamdownsmall +f7a2 centoldstyle +f7a8 Dieresissmall +f7af Macronsmall +f7b4 Acutesmall +f7b8 Cedillasmall +f7bf questiondownsmall +f7e0 Agravesmall +f7e1 Aacutesmall +f7e2 Acircumflexsmall +f7e3 Atildesmall +f7e4 Adieresissmall +f7e5 Aringsmall +f7e6 AEsmall +f7e7 Ccedillasmall +f7e8 Egravesmall +f7e9 Eacutesmall +f7ea Ecircumflexsmall +f7eb Edieresissmall +f7ec Igravesmall +f7ed Iacutesmall +f7ee Icircumflexsmall +f7ef Idieresissmall +f7f0 Ethsmall +f7f1 Ntildesmall +f7f2 Ogravesmall +f7f3 Oacutesmall +f7f4 Ocircumflexsmall +f7f5 Otildesmall +f7f6 Odieresissmall +f7f8 Oslashsmall +f7f9 Ugravesmall +f7fa Uacutesmall +f7fb Ucircumflexsmall +f7fc Udieresissmall +f7fd Yacutesmall +f7fe Thornsmall +f7ff Ydieresissmall +f8e5 radicalex +f8e6 arrowvertex +f8e7 arrowhorizex +f8e8 registersans +f8e9 copyrightsans +f8ea trademarksans +f8eb parenlefttp +f8ec parenleftex +f8ed parenleftbt +f8ee bracketlefttp +f8ef bracketleftex +f8f0 bracketleftbt +f8f1 bracelefttp +f8f2 braceleftmid +f8f3 braceleftbt +f8f4 braceex +f8f5 integralex +f8f6 parenrighttp +f8f7 parenrightex +f8f8 parenrightbt +f8f9 bracketrighttp +f8fa bracketrightex +f8fb bracketrightbt +f8fc bracerighttp +f8fd bracerightmid +f8fe bracerightbt +fb00 ff +fb01 fi +fb02 fl +fb03 ffi +fb04 ffl +fb1f afii57705 +fb2a afii57694 +fb2b afii57695 +fb35 afii57723 +fb4b afii57700 diff --git a/data/secret b/data/secret new file mode 100644 index 0000000000..6d66a3b928 --- /dev/null +++ b/data/secret @@ -0,0 +1,277 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the label at the top and bottom... + 0 setgray % Color + + pageWidth 36 mul % Center of page + pageHeight 72 mul % Top of page + pageWidth -7 mul add % - 2 lines + moveto % Position text + bigFont setfont % Font + (Secret) CENTER % Show text centered + + pageWidth 36 mul % Center of page + pageHeight 6 mul % Bottom of page + moveto % Position text + bigFont setfont % Font + (Secret) CENTER % Show text centered + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: secret 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/standard b/data/standard new file mode 100644 index 0000000000..c637ba7e04 --- /dev/null +++ b/data/standard @@ -0,0 +1,261 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: standard 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/testprint.ps b/data/testprint.ps new file mode 100644 index 0000000000..5a5e802614 --- /dev/null +++ b/data/testprint.ps @@ -0,0 +1,522 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset testprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 11, 1999 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset testprint 1.1 0 +% +% PostScript test page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/OCTANT { % Draw a color wheel OCTANT... + % (name) radius r g b OCTANT - + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + 3 index 1 eq % R == 1? + 3 index 1 eq % G == 1? + 3 index 1 eq % B == 1? + and and { + 0 index 4 index mul % R * val + 1 index 4 index mul % G * val + 2 index 4 index mul % B * val + } { + 0 index 4 index mul % R * val + 1 index neg 1 add add % + (1 - val) + 1 index 4 index mul % G * val + 2 index neg 1 add add % + (1 - val) + 2 index 4 index mul % B * val + 3 index neg 1 add add % + (1 - val) + } ifelse + setrgbcolor + + % Draw a polygon... + dup 5 index mul dup 0 % x1, y1 + moveto + 0.707106781 mul dup lineto % x2, y2 + + 0.010101 add 4 index mul dup % x3 + 0.707106781 mul dup lineto % x3, y3 + 0 lineto % x4, y4 + closepath + fill + } for + + % Draw a line around the polygons... + pop pop pop dup + 0 setgray + 0 0 moveto + dup 0 lineto + 0.707106781 mul dup lineto + closepath + stroke + + % Draw the label... + 0 exch dup -9 div exch % text offset = 0, -radius/9 + dup 0.923879532 mul % x = radius * cos(22.5) + exch 0.382683432 mul % y = radius * cos(22.5) + moveto % position label + gsave + 22.5 rotate % rotate label + rmoveto % offset label + show % show label + grestore +} bind def +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + 4 setlinewidth % Draw wide lines + 0 setgray closepath stroke % Draw a clipping rectangle + 1 setlinewidth % Draw normal lines + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + 72 72 dtransform % Get device resolution per inch + /yResolution exch abs def % yResolution = abs(yres) + /xResolution exch abs def % xResolution = abs(xres) + + % Figure out the sizes of things... + /wheelSize % size of wheels + pageWidth pageHeight lt + { pageWidth 9 mul } + { pageHeight 7 mul } + ifelse def + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + /smallFont /Times-Roman findfont % smallFont = Times-Roman + pageHeight scalefont def % size = pageHeight (nominally 11) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the color wheel... + mediumFont setfont % Font + 0 setgray % Color + + gsave + % Position the wheel on the left side... + pageWidth 18 mul % x = pageWidth * 1/4 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + translate + + % Size the wheel... + wheelSize + + % Draw the colors... + dup (C) exch 0 1 1 OCTANT 45 rotate + dup (M) exch 1 0 1 OCTANT 45 rotate + dup (Y) exch 1 1 0 OCTANT 45 rotate + dup (K) exch 0 0 0 OCTANT 45 rotate + dup (R) exch 1 0 0 OCTANT 45 rotate + dup (G) exch 0 1 0 OCTANT 45 rotate + dup (B) exch 0 0 1 OCTANT 45 rotate + (W) exch 1 1 1 OCTANT 45 rotate + grestore + + % Label the color wheel... + pageWidth 18 mul % x = pageWidth * 1/4 * 72 + pageHeight 44 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (Color Wheel) CENTER % Show the text centered + + % Draw radial lines... + gsave + 0 setlinewidth % 1 pixel lines + + % Position the lines on the left side... + pageWidth 54 mul % x = pageWidth * 3/4 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + translate + + % Size the wheel... + wheelSize + + % Loop at 1 degree increments + 0 1 359 { + pop % Discard angle - not used + 0 0 moveto % Start line at the center + dup 0 lineto % Draw to the radius + 1 rotate % Rotate 1 degree + } for + + pop % Discard radius - not needed anymore + stroke % Draw lines... + + grestore + + % Label the lines... + pageWidth 54 mul % x = pageWidth * 3/4 * 72 + pageHeight 44 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (1 Degree Radial Lines) CENTER % Show the text centered + + % Imageable area... + pageHeight 15 mul % Height of imageable area + + pageWidth 4.5 mul % x = pageWidth * 1/16 * 72 + pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 1/4 * 72 + 3 index % height + 0.5 setgray rectfill % Draw a shadow + + pageWidth 4 mul % x = pageWidth * 1/16 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 3/8 * 72 + 3 index % height + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + pop % Discard height + + % Label the imageable area... + pageWidth 4 mul % x = pageWidth * 1/16 * 72 + pageHeight 37 mul % y = pageHeight * 1/2 * 72 + moveto % Position the text + mediumFont setfont % Font + (Imageable Area) show % Show the text + + smallFont setfont % Font + pageWidth 14 mul % x = pageWidth * 3/16 * 72 + pageHeight 36 mul % y = pageWidth * 1/2 * 72 + pageHeight -2 mul add % y -= 2 * smallFont height + + % Page Size inches + 2 copy moveto % Move to x & y + (Page Size: ) RIGHT % Label + 100 pageWidth NUMBER % pageWidth + (x) show % "x" + 100 pageHeight NUMBER % pageHeight + (in) show % "in" + + % Page Size millimeters + pageHeight sub % Move down... + + 2 copy moveto % Move to x & y + 10 pageWidth 25.4 mul NUMBER % pageWidth + (x) show % "x" + 10 pageHeight 25.4 mul NUMBER % pageHeight + (mm) show % "mm" + + % Lower-left inches + pageHeight 2 mul sub % Move down... + + 2 copy moveto % Move to x & y + (Lower-Left: ) RIGHT % Label + 100 pageLeft NUMBER % pageLeft + (x) show % "x" + 100 pageBottom NUMBER % pageBottom + (in) show % "in" + + % Lower-left millimeters + pageHeight sub % Move down... + + 2 copy moveto % Move to x & y + 10 pageLeft 25.4 mul NUMBER % pageLeft + (x) show % "x" + 10 pageBottom 25.4 mul NUMBER % pageBottom + (mm) show % "mm" + + % Upper-right inches + pageHeight 2 mul sub % Move down... + + 2 copy moveto % Move to x & y + (Upper-Right: ) RIGHT % Label + 100 pageRight NUMBER % pageRight + (x) show % "x" + 100 pageTop NUMBER % pageTop + (in) show % "in" + + % Upper-right millimeters + pageHeight sub % Move down... + + 2 copy moveto % Move to x & y + 10 pageRight 25.4 mul NUMBER % pageRight + (x) show % "x" + 10 pageTop 25.4 mul NUMBER % pageTop + (mm) show % "mm" + + % Resolution dots-per-inch + pageHeight 2 mul sub % Move down... + + 2 copy moveto % Move to x & y + (Resolution: ) RIGHT % Label + 1 xResolution NUMBER % xResolution + (x) show % "x" + 1 yResolution NUMBER % yResolution + (dpi) show % "dpi" + + % Resolution dots-per-meter + pageHeight sub % Move down... + + moveto % Move to x & y + 1 xResolution 39.27 mul NUMBER % xResolution + (x) show % "x" + 1 yResolution 39.27 mul NUMBER % yResolution + (dpm) show % "dpm" + + % Interpreter Information... + pageHeight 15 mul % Height of interpreter information + + pageWidth 40.5 mul % x = pageWidth * 9/16 * 72 + pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 1/4 * 72 + 3 index % height + 0.5 setgray rectfill % Draw a shadow + + pageWidth 40 mul % x = pageWidth * 9/16 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 3/8 * 72 + 3 index % height + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + pop % Discard height + + % Label the interpreter info... + pageWidth 40 mul % x = pageWidth * 9/16 * 72 + pageHeight 37 mul % y = pageHeight * 1/2 * 72 + moveto % Position the text + mediumFont setfont % Font + (Interpreter Information) show % Show the text + + smallFont setfont % Font + pageWidth 49 mul % x = pageWidth * 11/16 * 72 + pageHeight 36 mul % y = pageWidth * 1/2 * 72 + pageHeight 2 mul sub % y -= 2 * smallFont height + + % Language level + 2 copy moveto % Move to x & y + (PostScript: ) RIGHT % Label + (Level ) show % "Level " + 1 languagelevel NUMBER % Language level + + % Version + pageHeight 2 mul sub % Move down... + 2 copy moveto % Move to x & y + (Version: ) RIGHT % Label + version show % Version + ( \() show % " (" + 1 revision NUMBER % Revision + (\)) show % ")" + + % Product + pageHeight 2 mul sub % Move down... + 2 copy moveto % Move to x & y + (Product: ) RIGHT % Label + product show % Product name + + % Serial Number + pageHeight 2 mul sub % Move down... + 2 copy moveto % Move to x & y + (Serial #: ) RIGHT % Label + 1 serialnumber NUMBER % S/N + + % Draw the label at the top... + pageWidth 36 mul % Center of page + pageHeight 68 mul % Top of page (15/16ths) + 2 copy moveto % Position text + bigFont setfont % Font + (Printer Test Page) CENTER % Show text centered + + % Draw the copyright notice at the bottom... + pageWidth 36 mul % Center of page + pageHeight 10 mul % Bottom of page + 2 copy moveto % Position text + (Printed Using CUPS v1.1.x) CENTER % Show text centered + + pageHeight 2 mul sub % Move down... + 2 copy moveto % Position text + smallFont setfont % Font + (Copyright 1993-2001 Easy Software Products, All Rights Reserved.) CENTER + pageHeight sub % Move down... + 2 copy moveto % Position text + (CUPS, and the CUPS logo are the trademark property of) CENTER + pageHeight sub % Move down... + 2 copy moveto % Position text + (Easy Software Products, 44141 Airport View Drive, Suite 204,) CENTER + pageHeight sub % Move down... + 2 copy moveto % Position text + (Hollywood, Maryland, 20636-3111, USA.) CENTER + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageHeight 4 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageHeight 4 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: testprint.ps 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/topsecret b/data/topsecret new file mode 100644 index 0000000000..029d22c394 --- /dev/null +++ b/data/topsecret @@ -0,0 +1,277 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the label at the top and bottom... + 0 setgray % Color + + pageWidth 36 mul % Center of page + pageHeight 72 mul % Top of page + pageWidth -7 mul add % - 2 lines + moveto % Position text + bigFont setfont % Font + (Top Secret) CENTER % Show text centered + + pageWidth 36 mul % Center of page + pageHeight 6 mul % Bottom of page + moveto % Position text + bigFont setfont % Font + (Top Secret) CENTER % Show text centered + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: topsecret 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/unclassified b/data/unclassified new file mode 100644 index 0000000000..7917334f10 --- /dev/null +++ b/data/unclassified @@ -0,0 +1,277 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset bannerprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 10, 2000 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset bannerprint 1.1 0 +% +% PostScript banner page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2001 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + /boxWidth % width of text box + pageWidth pageHeight lt + { pageWidth 54 mul } + { pageHeight 42 mul } + ifelse def + + newpath % Clear bounding path + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the label at the top and bottom... + 0 setgray % Color + + pageWidth 36 mul % Center of page + pageHeight 72 mul % Top of page + pageWidth -7 mul add % - 2 lines + moveto % Position text + bigFont setfont % Font + (Unclassified) CENTER % Show text centered + + pageWidth 36 mul % Center of page + pageHeight 6 mul % Bottom of page + moveto % Position text + bigFont setfont % Font + (Unclassified) CENTER % Show text centered + + % Job information box... + pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + 0.5 setgray rectfill % Draw a shadow + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + boxWidth 0.5 mul sub % x-= 1/2 box width + pageHeight 30 mul % y = pageHeight * 1/4 * 72 + boxWidth % w = box width + pageHeight 14 mul % h = pageHeight * 1/2 * 72 + + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + % Job information text... + mediumFont setfont % Medium sized font + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 5 mul add % y += 2 lines + 2 copy % Copy X & Y + moveto + (Job ID: ) RIGHT + moveto + ({printer-name}-{job-id}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight 2 mul add % y += 1 line + 2 copy % Copy X & Y + moveto + (Title: ) RIGHT + moveto + ({job-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -1 mul add % y -= 1 line + 2 copy % Copy X & Y + moveto + (Requesting User: ) RIGHT + moveto + ({job-originating-user-name}) show + + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + pageHeight -4 mul add % y -= 2 lines + 2 copy % Copy X & Y + moveto + (Billing Info: ) RIGHT + moveto + ({job-billing}) show + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: unclassified 1646 2001-03-25 12:42:57Z mike $". +% +%%EOF diff --git a/data/utf-8 b/data/utf-8 new file mode 100644 index 0000000000..e808223a06 --- /dev/null +++ b/data/utf-8 @@ -0,0 +1,38 @@ +charset utf8 + +# +# This file defines the font mappings used for Unicode/UTF-8 text printing. +# +# Each line consists of: +# +# first last direction width normal bold italic bold-italic +# +# First and last are the first and last glyphs in the font mapping +# that correspond to that font; a maximum of 256 characters can be +# mapped within each group, with a maximum of 256 mappings (this is a +# PostScript limitation.) The glyph values are hexadecimal. +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +0000 00FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0100 01FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0200 02FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0300 03FF ltor single Symbol +0400 04FF ltor single Courier-Cyrillic +1E00 1EFF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2000 20FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2100 21FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2200 22FF ltor single Symbol +2300 23FF ltor single Symbol diff --git a/data/windows-1250 b/data/windows-1250 new file mode 100644 index 0000000000..afcc62ed5f --- /dev/null +++ b/data/windows-1250 @@ -0,0 +1,254 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1250 (WinLatin2) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8A 0160 +8B 2039 +8C 015A +8D 0164 +8E 017D +8F 0179 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0161 +9B 203A +9C 015B +9D 0165 +9E 017E +9F 017A +A0 00A0 +A1 02C7 +A2 02D8 +A3 0141 +A4 00A4 +A5 0104 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 015E +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 017B +B0 00B0 +B1 00B1 +B2 02DB +B3 0142 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 0105 +BA 015F +BB 00BB +BC 013D +BD 02DD +BE 013E +BF 017C +C0 0154 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 0139 +C6 0106 +C7 00C7 +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 011A +CD 00CD +CE 00CE +CF 010E +D0 0110 +D1 0143 +D2 0147 +D3 00D3 +D4 00D4 +D5 0150 +D6 00D6 +D7 00D7 +D8 0158 +D9 016E +DA 00DA +DB 0170 +DC 00DC +DD 00DD +DE 0162 +DF 00DF +E0 0155 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 013A +E6 0107 +E7 00E7 +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 011B +ED 00ED +EE 00EE +EF 010F +F0 0111 +F1 0144 +F2 0148 +F3 00F3 +F4 00F4 +F5 0151 +F6 00F6 +F7 00F7 +F8 0159 +F9 016F +FA 00FA +FB 0171 +FC 00FC +FD 00FD +FE 0163 +FF 02D9 diff --git a/data/windows-1251 b/data/windows-1251 new file mode 100644 index 0000000000..6d31dee09c --- /dev/null +++ b/data/windows-1251 @@ -0,0 +1,258 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1251 (WinCyrillic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 0402 +81 0403 +82 201A +83 0453 +84 201E +85 2026 +86 2020 +87 2021 +88 20AC +89 2030 +8A 0409 +8B 2039 +8C 040A +8D 040C +8E 040B +8F 040F +90 0452 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0459 +9B 203A +9C 045A +9D 045C +9E 045B +9F 045F +A0 00A0 +A1 040E +A2 045E +A3 0408 +A4 00A4 +A5 0490 +A6 00A6 +A7 00A7 +A8 0401 +A9 00A9 +AA 0404 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 0407 +B0 00B0 +B1 00B1 +B2 0406 +B3 0456 +B4 0491 +B5 00B5 +B6 00B6 +B7 00B7 +B8 0451 +B9 2116 +BA 0454 +BB 00BB +BC 0458 +BD 0405 +BE 0455 +BF 0457 +C0 0410 +C1 0411 +C2 0412 +C3 0413 +C4 0414 +C5 0415 +C6 0416 +C7 0417 +C8 0418 +C9 0419 +CA 041A +CB 041B +CC 041C +CD 041D +CE 041E +CF 041F +D0 0420 +D1 0421 +D2 0422 +D3 0423 +D4 0424 +D5 0425 +D6 0426 +D7 0427 +D8 0428 +D9 0429 +DA 042A +DB 042B +DC 042C +DD 042D +DE 042E +DF 042F +E0 0430 +E1 0431 +E2 0432 +E3 0433 +E4 0434 +E5 0435 +E6 0436 +E7 0437 +E8 0438 +E9 0439 +EA 043A +EB 043B +EC 043C +ED 043D +EE 043E +EF 043F +F0 0440 +F1 0441 +F2 0442 +F3 0443 +F4 0444 +F5 0445 +F6 0446 +F7 0447 +F8 0448 +F9 0449 +FA 044A +FB 044B +FC 044C +FD 044D +FE 044E +FF 044F diff --git a/data/windows-1252 b/data/windows-1252 new file mode 100644 index 0000000000..a98595874d --- /dev/null +++ b/data/windows-1252 @@ -0,0 +1,254 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1252 (WinLatin1) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +8E 017D +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9E 017E +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/windows-1253 b/data/windows-1253 new file mode 100644 index 0000000000..c736ecd6c8 --- /dev/null +++ b/data/windows-1253 @@ -0,0 +1,243 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1253 (WinGreek) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 9f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic +a0 ff ltor single Symbol + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8B 2039 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9B 203A +A0 00A0 +A1 0385 +A2 0386 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 2015 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 0384 +B5 00B5 +B6 00B6 +B7 00B7 +B8 0388 +B9 0389 +BA 038A +BB 00BB +BC 038C +BD 00BD +BE 038E +BF 038F +C0 0390 +C1 0391 +C2 0392 +C3 0393 +C4 0394 +C5 0395 +C6 0396 +C7 0397 +C8 0398 +C9 0399 +CA 039A +CB 039B +CC 039C +CD 039D +CE 039E +CF 039F +D0 03A0 +D1 03A1 +D3 03A3 +D4 03A4 +D5 03A5 +D6 03A6 +D7 03A7 +D8 03A8 +D9 03A9 +DA 03AA +DB 03AB +DC 03AC +DD 03AD +DE 03AE +DF 03AF +E0 03B0 +E1 03B1 +E2 03B2 +E3 03B3 +E4 03B4 +E5 03B5 +E6 03B6 +E7 03B7 +E8 03B8 +E9 03B9 +EA 03BA +EB 03BB +EC 03BC +ED 03BD +EE 03BE +EF 03BF +F0 03C0 +F1 03C1 +F2 03C2 +F3 03C3 +F4 03C4 +F5 03C5 +F6 03C6 +F7 03C7 +F8 03C8 +F9 03C9 +FA 03CA +FB 03CB +FC 03CC +FD 03CD +FE 03CE diff --git a/data/windows-1254 b/data/windows-1254 new file mode 100644 index 0000000000..87fff2db7e --- /dev/null +++ b/data/windows-1254 @@ -0,0 +1,252 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1254 (WinTurkish) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 011E +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 0130 +DE 015E +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 011F +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 0131 +FE 015F +FF 00FF diff --git a/data/windows-1255 b/data/windows-1255 new file mode 100644 index 0000000000..a8b26a85d9 --- /dev/null +++ b/data/windows-1255 @@ -0,0 +1,236 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1255 (WinHebrew) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8B 2039 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9B 203A +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 20AA +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00D7 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00F7 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 05B0 +C1 05B1 +C2 05B2 +C3 05B3 +C4 05B4 +C5 05B5 +C6 05B6 +C7 05B7 +C8 05B8 +C9 05B9 +CB 05BB +CC 05BC +CD 05BD +CE 05BE +CF 05BF +D0 05C0 +D1 05C1 +D2 05C2 +D3 05C3 +D4 05F0 +D5 05F1 +D6 05F2 +D7 05F3 +D8 05F4 +E0 05D0 +E1 05D1 +E2 05D2 +E3 05D3 +E4 05D4 +E5 05D5 +E6 05D6 +E7 05D7 +E8 05D8 +E9 05D9 +EA 05DA +EB 05DB +EC 05DC +ED 05DD +EE 05DE +EF 05DF +F0 05E0 +F1 05E1 +F2 05E2 +F3 05E3 +F4 05E4 +F5 05E5 +F6 05E6 +F7 05E7 +F8 05E8 +F9 05E9 +FA 05EA +FD 200E +FE 200F diff --git a/data/windows-1256 b/data/windows-1256 new file mode 100644 index 0000000000..6908f1eb5a --- /dev/null +++ b/data/windows-1256 @@ -0,0 +1,259 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1256 (WinArabic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +81 067E +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0679 +8B 2039 +8C 0152 +8D 0686 +8E 0698 +8F 0688 +90 06AF +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 06A9 +99 2122 +9A 0691 +9B 203A +9C 0153 +9D 200C +9E 200D +9F 06BA +A0 00A0 +A1 060C +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 06BE +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 061B +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 061F +C0 06C1 +C1 0621 +C2 0622 +C3 0623 +C4 0624 +C5 0625 +C6 0626 +C7 0627 +C8 0628 +C9 0629 +CA 062A +CB 062B +CC 062C +CD 062D +CE 062E +CF 062F +D0 0630 +D1 0631 +D2 0632 +D3 0633 +D4 0634 +D5 0635 +D6 0636 +D7 00D7 +D8 0637 +D9 0638 +DA 0639 +DB 063A +DC 0640 +DD 0641 +DE 0642 +DF 0643 +E0 00E0 +E1 0644 +E2 00E2 +E3 0645 +E4 0646 +E5 0647 +E6 0648 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 0649 +ED 064A +EE 00EE +EF 00EF +F0 064B +F1 064C +F2 064D +F3 064E +F4 00F4 +F5 064F +F6 0650 +F7 00F7 +F8 0651 +F9 00F9 +FA 0652 +FB 00FB +FC 00FC +FD 200E +FE 200F +FF 06D2 diff --git a/data/windows-1257 b/data/windows-1257 new file mode 100644 index 0000000000..ac5f8e0b7c --- /dev/null +++ b/data/windows-1257 @@ -0,0 +1,247 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1257 (WinBaltic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8B 2039 +8D 00A8 +8E 02C7 +8F 00B8 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9B 203A +9D 00AF +9E 02DB +A0 00A0 +A2 00A2 +A3 00A3 +A4 00A4 +A6 00A6 +A7 00A7 +A8 00D8 +A9 00A9 +AA 0156 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00C6 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00F8 +B9 00B9 +BA 0157 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00E6 +C0 0104 +C1 012E +C2 0100 +C3 0106 +C4 00C4 +C5 00C5 +C6 0118 +C7 0112 +C8 010C +C9 00C9 +CA 0179 +CB 0116 +CC 0122 +CD 0136 +CE 012A +CF 013B +D0 0160 +D1 0143 +D2 0145 +D3 00D3 +D4 014C +D5 00D5 +D6 00D6 +D7 00D7 +D8 0172 +D9 0141 +DA 015A +DB 016A +DC 00DC +DD 017B +DE 017D +DF 00DF +E0 0105 +E1 012F +E2 0101 +E3 0107 +E4 00E4 +E5 00E5 +E6 0119 +E7 0113 +E8 010D +E9 00E9 +EA 017A +EB 0117 +EC 0123 +ED 0137 +EE 012B +EF 013C +F0 0161 +F1 0144 +F2 0146 +F3 00F3 +F4 014D +F5 00F5 +F6 00F6 +F7 00F7 +F8 0173 +F9 0142 +FA 015B +FB 016B +FC 00FC +FD 017C +FE 017E +FF 02D9 diff --git a/data/windows-1258 b/data/windows-1258 new file mode 100644 index 0000000000..f7721c51b1 --- /dev/null +++ b/data/windows-1258 @@ -0,0 +1,250 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1258 (WinVietnamese) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 0300 +CD 00CD +CE 00CE +CF 00CF +D0 0110 +D1 00D1 +D2 0309 +D3 00D3 +D4 00D4 +D5 01A0 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 01AF +DE 0303 +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 0301 +ED 00ED +EE 00EE +EF 00EF +F0 0111 +F1 00F1 +F2 0323 +F3 00F3 +F4 00F4 +F5 01A1 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 01B0 +FE 20AB +FF 00FF diff --git a/data/windows-874 b/data/windows-874 new file mode 100644 index 0000000000..886e46a4b4 --- /dev/null +++ b/data/windows-874 @@ -0,0 +1,228 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 874 (Thai) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +00 ff ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +85 2026 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +A0 00A0 +A1 0E01 +A2 0E02 +A3 0E03 +A4 0E04 +A5 0E05 +A6 0E06 +A7 0E07 +A8 0E08 +A9 0E09 +AA 0E0A +AB 0E0B +AC 0E0C +AD 0E0D +AE 0E0E +AF 0E0F +B0 0E10 +B1 0E11 +B2 0E12 +B3 0E13 +B4 0E14 +B5 0E15 +B6 0E16 +B7 0E17 +B8 0E18 +B9 0E19 +BA 0E1A +BB 0E1B +BC 0E1C +BD 0E1D +BE 0E1E +BF 0E1F +C0 0E20 +C1 0E21 +C2 0E22 +C3 0E23 +C4 0E24 +C5 0E25 +C6 0E26 +C7 0E27 +C8 0E28 +C9 0E29 +CA 0E2A +CB 0E2B +CC 0E2C +CD 0E2D +CE 0E2E +CF 0E2F +D0 0E30 +D1 0E31 +D2 0E32 +D3 0E33 +D4 0E34 +D5 0E35 +D6 0E36 +D7 0E37 +D8 0E38 +D9 0E39 +DA 0E3A +DF 0E3F +E0 0E40 +E1 0E41 +E2 0E42 +E3 0E43 +E4 0E44 +E5 0E45 +E6 0E46 +E7 0E47 +E8 0E48 +E9 0E49 +EA 0E4A +EB 0E4B +EC 0E4C +ED 0E4D +EE 0E4E +EF 0E4F +F0 0E50 +F1 0E51 +F2 0E52 +F3 0E53 +F4 0E54 +F5 0E55 +F6 0E56 +F7 0E57 +F8 0E58 +F9 0E59 +FA 0E5A +FB 0E5B diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000..e04c98eeca --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,230 @@ +# +# "$Id$" +# +# Documentation makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2001 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# HTMLDOC generation rules... +# + +.SUFFIXES: .html .pdf .ps .shtml +.shtml.html: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --numbered -f $@ $< +.shtml.pdf: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --numbered --jpeg -f $@ $< +.shtml.ps: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --numbered \ + --jpeg -f $@ $< + + +# +# Document files... +# + +DOCUMENTS = cmp.shtml idd.shtml ipp.shtml sam.shtml sdd.shtml \ + spm.shtml sps.shtml ssr.shtml stp.shtml sum.shtml \ + svd.shtml +DOCIMAGES = images/cups-block-diagram.gif images/cups-large.gif \ + images/cups-medium.gif images/cups-small.gif +WEBPAGES = cups.css cupsdoc.css index.html documentation.html +WEBIMAGES = images/accept-jobs.gif \ + images/add-class.gif \ + images/add-printer.gif \ + images/cancel-job.gif \ + images/cancel-jobs.gif \ + images/cancel.gif \ + images/classes.gif \ + images/config-printer.gif \ + images/continue.gif \ + images/delete-class.gif \ + images/delete-printer.gif \ + images/draft.gif \ + images/hold-job.gif \ + images/left.gif \ + images/logo.gif \ + images/manage-classes.gif \ + images/manage-jobs.gif \ + images/manage-printers.gif \ + images/modify-class.gif \ + images/modify-printer.gif \ + images/navbar.gif \ + images/print-test-page.gif \ + images/printer-idle.gif \ + images/printer-processing.gif \ + images/printer-stopped.gif \ + images/reject-jobs.gif \ + images/release-job.gif \ + images/restart-job.gif \ + images/right.gif \ + images/show-active.gif \ + images/show-completed.gif \ + images/start-class.gif \ + images/start-printer.gif \ + images/stop-class.gif \ + images/stop-printer.gif + + +# +# Make all documents... +# + +all: $(DOCUMENTS:.shtml=.pdf) $(DOCUMENTS:.shtml=.html) overview.pdf + + +# +# Make PS files... +# + +ps: $(DOCUMENTS:.shtml=.ps) overview.ps + + +# +# Remove all generated files... +# + +clean: + $(RM) $(DOCUMENTS:.shtml=.pdf) + $(RM) $(DOCUMENTS:.shtml=.html) + $(RM) overview.pdf + + +# +# Install all documentation files... +# + +install: + -$(MKDIR) $(DOCDIR) + $(CHMOD) ugo+rx $(DOCDIR) + $(INSTALL_MAN) $(WEBPAGES) $(DOCDIR) + $(INSTALL_MAN) overview.html overview.pdf $(DOCDIR) + $(INSTALL_MAN) $(DOCUMENTS:.shtml=.html) $(DOCDIR) + $(INSTALL_MAN) $(DOCUMENTS:.shtml=.pdf) $(DOCDIR) + -$(MKDIR) $(DOCDIR)/images + $(CHMOD) ugo+rx $(DOCDIR)/images + $(INSTALL_MAN) $(WEBIMAGES) $(DOCDIR)/images + $(INSTALL_MAN) $(DOCIMAGES) $(DOCDIR)/images + + +# +# The overview, admin manual, programmers manual, and users manual get +# special attention... +# + +overview.pdf: overview.html + echo Formatting $@... + htmldoc --duplex --compression=9 --jpeg --webpage -f overview.pdf overview.html +overview.ps: overview.html + echo Formatting $@... + htmldoc --duplex --jpeg --webpage -f overview.ps overview.html + +sam.html: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +sam.pdf: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< +sam.ps: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg -f $@ $< + +spm.html: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +spm.pdf: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< +spm.ps: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg -f $@ $< + +sum.html: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +sum.pdf: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< +sum.ps: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg -f $@ $< + +sam-7x8.pdf: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --pagelayout tworight --pagemode document \ + --jpeg --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sam.shtml +sam-7x8.ps: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg \ + --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sam.shtml +spm-7x8.pdf: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --pagelayout tworight --pagemode document \ + --jpeg --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ spm.shtml +spm-7x8.ps: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg \ + --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ spm.shtml +sum-7x8.pdf: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --pagelayout tworight --pagemode document \ + --jpeg --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sum.shtml +sum-7x8.ps: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --jpeg \ + --size 7x8.5in --left 0.5in --right 0.25in \ + --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sum.shtml + +$(DOCUMENTS:.shtml=.html): \ + glossary.shtml printing-overview.shtml \ + references.shtml system-overview.shtml \ + ../LICENSE.html + +$(DOCUMENTS:.shtml=.pdf): \ + glossary.shtml printing-overview.shtml \ + references.shtml system-overview.shtml \ + ../LICENSE.html + +$(DOCUMENTS:.shtml=.ps): \ + glossary.shtml printing-overview.shtml \ + references.shtml system-overview.shtml \ + ../LICENSE.html + + +# +# End of Makefile. +# diff --git a/doc/cmp.html b/doc/cmp.html new file mode 100644 index 0000000000..a950f872b8 --- /dev/null +++ b/doc/cmp.html @@ -0,0 +1,678 @@ + + + + CUPS Configuration Management Plan + + + + + + + +

+

CUPS Configuration Management Plan


+CUPS-CMP-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 File Management + +4 Trouble Report Processing + +5 Software Releases + +A Glossary + +B Coding Requirements + +C Software Trouble Report Form
+

1 Scope

+

1.1 Identification

+ This configuration management plan document provides the guidelines +for development and maintenance of the Common UNIX Printing System +("CUPS") Version 1.1 software. +

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+ This configuration management document is organized into the following +sections: +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - File Management
  • +
  • 4 - Trouble Report Processing
  • +
  • 5 - Software Releases
  • +
  • A - Glossary
  • +
  • B - Coding Requirements
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 File Management

+

3.1 Directory Structure

+ Each source file shall be placed a sub-directory corresponding to the +software sub-system it belongs to ("scheduler", "cups", etc.) To remain +compatible with older UNIX filesystems, directory names shall not +exceed 16 characters in length. +

3.2 Source Files

+ Source files shall be documented and formatted as described in +Appendix B, Coding Requirements. +

3.3 Configuration Management

+ Source files shall be placed under the control of the Concurrent +Versions System ("CVS") software. Source files shall be "checked in" +with each change so that modifications can be tracked. +

Documentation on the CVS software is included with the whitepaper, +"CVS II: Parallelizing Software Development".

+

4 Trouble Report Processing

+ A Software Trouble Report ("STR") shall be submitted every time a user +or vendor experiences a problem with the CUPS software. Trouble reports +are maintained in a database with one of the following states: +
    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active
  6. +
  7. STR is pending (new STR or additional information available)
  8. +
+ Trouble reports shall be processed using the following steps. +

4.1 Classification

+ When a trouble report is received it must be classified at one of the +following levels: +
    +
  1. Request for enhancement
  2. +
  3. Documentation error
  4. +
  5. Unable to print a file
  6. +
  7. Unable to print to a printer
  8. +
  9. Unable to print at all
  10. +
+ The scope of the problem should also be determined as: +
    +
  1. Specific to a machine
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines and operating systems
  6. +
+

4.2 Identification

+ Once the level and scope of the trouble report is determined the +software sub-system(s) involved with the problem are determined. This +may involve additional communication with the user or vendor to isolate +the problem to a specific cause. +

When the sub-system(s) involved have been identified, an engineer +will then determine the change(s) needed and estimate the time required +for the change(s).

+

4.3 Correction

+ Corrections are scheduled based upon the severity and complexity of +the problem. Once all changes have been made, documented, and tested +successfully a new software release snapshot is generated. Additional +tests are added as necessary for proper testing of the changes. +

4.4 Notification

+ The user or vendor is notified when the fix is available or if the +problem was caused by user error. +

5 Software Releases

+

5.1 Version Numbering

+ CUPS uses a three-part version number separated by periods to +represent the major, minor, and patch release numbers: +
    +
    +major.minor.patch
    +1.1.0
    +
    +
+ Beta-test releases are indentified by appending the letter B followed +by the build number: +
    +
    +major.minor.patchbbuild
    +1.1.0b1
    +
    +
+ A CVS snapshot is generated for every beta and final release and uses +the version number preceded by the letter "v" and with the decimal +points replaced by underscores: +
    +
    +v1_0_0b1
    +v1_0_0
    +
    +
+ Each change that corrects a fault in a software sub-system increments +the patch release number. If a change affects the software design of +CUPS then the minor release number will be incremented and the patch +release number reset to 0. If CUPS is completely redesigned the major +release number will be incremented and the minor and patch release +numbers reset to 0: +
    +
    +1.1.0b1    First beta release
    +1.1.0b2    Second beta release
    +1.1.0      First production release
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +2.0.0b1    First beta of 2.0.0
    +2.0.0      Production release of 2.0.0
    +
    +
+

5.2 Generation

+ Software releases shall be generated for each successfully completed +software trouble report. All object and executable files shall be +deleted prior to performing a full build to ensure that source files +are recompiled. +

5.3 Testing

+ Software testing shall be conducted according to the CUPS Software +Test Plan, CUPS-STP-1.1. Failed tests cause STRs to be generated to +correct the problems found. +

5.4 Release

+ When testing has been completed successfully a new distribution image +is created from the current CVS code "snapshot". No production release +shall contain software that has not passed the appropriate software +tests. +

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+

B Coding Requirements

+ These coding requirements provide detailed information on source file +formatting and documentation content. These guidelines shall be applied +to all C and C++ source files provided with CUPS. +

B.1 Source Files

+

B.1.1 Naming

+ All source files names shall be 16 characters or less in length to +ensure compatibility with older UNIX filesystems. Source files +containing functions shall have an extension of ".c" for ANSI C and +".cxx" for C++ source files. All other "include" files shall have an +extension of ".h". +

B.1.2 Documentation

+ The top of each source file shall contain a header giving the name of +the file, the purpose or nature of the source file, the copyright and +licensing notice, and the functions contained in the file. The file +name and revision information is provided by the CVS "$Id$" tag: +
    +
    +/*
    + * "$Id$"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-2001 by Easy Software Products, all rights
    + *   reserved.
    + *
    + *   These coded instructions, statements, and computer programs are
    + *   the property of Easy Software Products and are protected by
    + *   Federal copyright law.  Distribution and use rights are outlined
    + *   in the file "LICENSE.txt" which should have been included with
    + *   this file.  If this file is missing or damaged please contact
    + *   Easy Software Products at:
    + *
    + *       Attn: CUPS Licensing Information
    + *       Easy Software Products
    + *       44141 Airport View Drive, Suite 204
    + *       Hollywood, Maryland 20636-3111 USA
    + *
    + *       Voice: (301) 373-9600
    + *       EMail: cups-info@cups.org
    + *         WWW: http://www.cups.org
    + *
    + * Contents:
    + *
    + *   function1() - Description 1.
    + *   function2() - Description 2.
    + *   function3() - Description 3.
    + */
    +
    +
+ The bottom of each source file shall contain a trailer giving the name +of the file using the CVS "$Id$" tag. The primary purpose of this is to +mark the end of a source file; if the trailer is missing it is possible +that code has been lost near the end of the file: +
    +
    +/*
    + * End of "$Id$".
    + */
    +
    +
+

B.2 Functions

+

B.2.1 Naming

+ Functions with a global scope shall be capitalized ("DoThis", +"DoThat", "DoSomethingElse", etc.) The only exception to this rule +shall be the CUPS interface library functions which may begin with a +prefix word in lowercase ("cupsDoThis", "cupsDoThat", etc.) +

Functions with a local scope shall be declared "static" and be +lowercase with underscores between words ("do_this", "do_that", +"do_something_else", etc.)

+

B.2.2 Documentation

+ Each function shall begin with a comment header describing what the +function does, the possible input limits (if any), and the possible +output values (if any), and any special information needed: +
    +
    +/*
    + * 'do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +static float     /* O - Inverse power value, 0.0 <= y <= 1.1 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */
    +{
    +  ...
    +  return (y);
    +}
    +
    +
+

B.3 Methods

+

B.3.1 Naming

+ Methods shall be in lowercase with underscores between words +("do_this", "do_that", "do_something_else", etc.) +

B.3.2 Documentation

+ Each method shall begin with a comment header describing what the +method does, the possible input limits (if any), and the possible +output values (if any), and any special information needed: +
    +
    +/*
    + * 'class::do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +float                   /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +class::do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    +  ...
    +  return (y);
    +}
    +
    +
+

B.4 Variables

+

B.4.1 Naming

+ Variables with a global scope shall be capitalized ("ThisVariable", +"ThatVariable", "ThisStateVariable", etc.) The only exception to this +rule shall be the CUPS interface library global variables which must +begin with the prefix "cups" ("cupsThisVariable", "cupsThatVariable", +etc.) Global variables shall be replaced by function arguments whenever +possible. +

Variables with a local scope shall be lowercase with underscores +between words ("this_variable", "that_variable", etc.) Any local +variables shared by functions within a source file shall be declared +"static".

+

B.4.2 Documentation

+ Each variable shall be declared on a separate line and shall be +immediately followed by a comment block describing the variable: +
    +
    +int this_variable;   /* The current state of this */
    +int that_variable;   /* The current state of that */
    +
    +
+

B.5 Types

+

B.5.1 Naming

+ All type names shall be lowercase with underscores between words and +"_t" appended to the end of the name ("this_type_t", "that_type_t", +etc.) +

B.5.2 Documentation

+ Each type shall have a comment block immediately before the typedef: +
    +
    +/*
    + * This type is for CUPS foobar options.
    + */
    +typedef int cups_this_type_t;
    +
    +
+

B.6 Structures

+

B.6.1 Naming

+ All structure names shall be lowercase with underscores between words +and "_str" appended to the end of the name ("this_struct_str", +"that_struct_str", etc.) +

B.6.2 Documentation

+ Each structure shall have a comment block immediately before the +struct and each member shall be documented in accordance with the +variable naming policy above: +
    +
    +/*
    + * This structure is for CUPS foobar options.
    + */
    +struct cups_this_struct_str
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+

B.7 Classes

+

B.7.1 Naming

+ All class names shall be lowercase with underscores between words +("this_class", "that_class", etc.) +

B.7.2 Documentation

+ Each class shall have a comment block immediately before the class and +each member shall be documented in accordance with the variable naming +policy above: +
    +
    +/*
    + * This class is for CUPS foobar options.
    + */
    +class cups_this_class
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+

B.8 Constants

+

B.8.1 Naming

+ All constant names shall be uppercase with underscored between words +("THIS_CONSTANT", "THAT_CONSTANT", etc.) Constants defined for the CUPS +interface library must begin with an uppercase prefix +("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.) +

Typed enumerations shall be used whenever possible to allow for type +checking by the compiler.

+

B.8.2 Documentation

+ Comment blocks shall immediately follow each constant: +
    +
    +enum
    +{
    +  CUPS_THIS_TRAY,   /* This tray */
    +  CUPS_THAT_TRAY    /* That tray */
    +};
    +
    +
+

B.9 Code

+

B.9.1 Documentation

+ All source code shall utilize block comments within functions to +describe the operations being performed by a group of statements: +
    +
    +/*
    + * Clear the state array before we begin...
    + */
    +
    +for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +  array[i] = STATE_IDLE;
    +
    +/*
    + * Wait for state changes...
    + */
    +
    +do
    +{
    +  for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +    if (array[i] != STATE_IDLE)
    +      break;
    +
    +  if (i == (sizeof(array) / sizeof(array[0])))
    +    sleep(1);
    +} while (i == (sizeof(array) / sizeof(array[0])));
    +
    +
+

B.9.2 Style

+

B.9.2.a Indentation

+ All code blocks enclosed by brackets shall begin with the opening +brace on a new line. The code then follows starting on a new line after +the brace and is indented 2 spaces. The closing brace is then placed on +a new line following the code at the original indentation: +
    +
    +{
    +  int i; /* Looping var */
    +
    + /*
    +  * Process foobar values from 0 to 999...
    +  */
    +
    +  for (i = 0; i < 1000; i ++)
    +  {
    +    do_this(i);
    +    do_that(i);
    +  }
    +}
    +
    +
+ Single-line statements following "do", "else", "for", "if", and +"while" shall be indented 2 spaces as well. Blocks of code in a +"switch" block shall be indented 4 spaces after each "case" and +"default" case: +
    +
    +switch (array[i])
    +{
    +  case STATE_IDLE :
    +      do_this(i);
    +      do_that(i);
    +      break;
    +  default :
    +      do_nothing(i);
    +      break;
    +}
    +
    +
+

B.9.2.b Spacing

+ A space shall follow each reserved word ("if", "while", etc.) Spaces +shall not be inserted between a function name and the arguments in +parenthesis. +

B.9.2.c Return Values

+ Parenthesis shall surround values returned from a function using +"return": +
    +
    +return (STATE_IDLE);
    +
    +
+

B.9.2.d Loops

+ Whenever convenient loops should count downward to zero to improve +program performance: +
    +
    +for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
    +  array[i] = STATE_IDLE;
    +
    +
+

C Software Trouble Report Form

+
+ + + + + +
Summary of Problem: +________________________________________
Problem Severity:__1=RFE +
__2=Documentation-Error +
__3=Unable-to-Print-a-File +
__4=Unable-to-Print-to-a-Printer +
__5=Unable-to-Print-at-All
Problem Scope:__1=Machine +__2=Operating-System __3=All
Detailed Description of Problem:________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________
+
+ + diff --git a/doc/cmp.pdf b/doc/cmp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..990f61b9662a1860145875e093aa1b4f6032abc7 GIT binary patch literal 54628 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 R1hIJUr{Lw4(~zh5{{Zqh<@W#p literal 0 Hc-jL100001 diff --git a/doc/cmp.shtml b/doc/cmp.shtml new file mode 100644 index 0000000000..163b58faf3 --- /dev/null +++ b/doc/cmp.shtml @@ -0,0 +1,595 @@ + + + + + + CUPS Configuration Management Plan + + + +

Scope

+ +

Identification

+ +This configuration management plan document provides the guidelines for +development and maintenance of the Common UNIX Printing System ("CUPS") +Version 1.1 software. + + + +

Document Overview

+ +This configuration management document is organized into the following +sections: + +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - File Management
  • +
  • 4 - Trouble Report Processing
  • +
  • 5 - Software Releases
  • +
  • A - Glossary
  • +
  • B - Coding Requirements
  • +
+ + + +

File Management

+ +

Directory Structure

+ +Each source file shall be placed a sub-directory corresponding to the software +sub-system it belongs to ("scheduler", "cups", etc.) To remain compatible +with older UNIX filesystems, directory names shall not exceed 16 characters +in length. + +

Source Files

+ +Source files shall be documented and formatted as described in Appendix +B, Coding Requirements. + +

Configuration Management

+ +Source files shall be placed under the control of the Concurrent Versions +System ("CVS") software. Source files shall be "checked in" with each change +so that modifications can be tracked. + +

Documentation on the CVS software is included with the whitepaper, "CVS +II: Parallelizing Software Development". + +

Trouble Report Processing

+ +A Software Trouble Report ("STR") shall be submitted every time a user +or vendor experiences a problem with the CUPS software. Trouble reports +are maintained in a database with one of the following states: + +
    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active
  6. +
  7. STR is pending (new STR or additional information available)
  8. +
+ +Trouble reports shall be processed using the following steps. + +

Classification

+ +When a trouble report is received it must be classified at one of the following +levels: + +
    +
  1. Request for enhancement
  2. +
  3. Documentation error
  4. +
  5. Unable to print a file
  6. +
  7. Unable to print to a printer
  8. +
  9. Unable to print at all
  10. +
+ +The scope of the problem should also be determined as: + +
    +
  1. Specific to a machine
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines and operating systems
  6. +
+ +

Identification

+ +Once the level and scope of the trouble report is determined the software +sub-system(s) involved with the problem are determined. This may involve +additional communication with the user or vendor to isolate the problem +to a specific cause. + +

When the sub-system(s) involved have been identified, an engineer will +then determine the change(s) needed and estimate the time required for +the change(s). + +

Correction

+ +Corrections are scheduled based upon the severity and complexity of the +problem. Once all changes have been made, documented, and tested successfully +a new software release snapshot is generated. Additional tests are added +as necessary for proper testing of the changes. + +

Notification

+ +The user or vendor is notified when the fix is available or if the problem +was caused by user error. + +

Software Releases

+ +

Version Numbering

+ +CUPS uses a three-part version number separated by periods to represent +the major, minor, and patch release numbers: + +
    +
    +major.minor.patch
    +1.1.0
    +
    +
+ +Beta-test releases are indentified by appending the letter B followed by +the build number: + +
    +
    +major.minor.patchbbuild
    +1.1.0b1
    +
    +
+ +A CVS snapshot is generated for every beta and final release and uses +the version number preceded by the letter "v" and with the decimal +points replaced by underscores: + +
    +
    +v1_0_0b1
    +v1_0_0
    +
    +
+ +Each change that corrects a fault in a software sub-system increments the +patch release number. If a change affects the software design of CUPS then +the minor release number will be incremented and the patch release number +reset to 0. If CUPS is completely redesigned the major release number will +be incremented and the minor and patch release numbers reset to 0: + +
    +
    +1.1.0b1    First beta release
    +1.1.0b2    Second beta release
    +1.1.0      First production release
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +2.0.0b1    First beta of 2.0.0
    +2.0.0      Production release of 2.0.0
    +
    +
+ +

Generation

+ +Software releases shall be generated for each successfully completed software +trouble report. All object and executable files shall be deleted prior +to performing a full build to ensure that source files are recompiled. + +

Testing

+ +Software testing shall be conducted according to the CUPS Software Test +Plan, CUPS-STP-1.1. Failed tests cause STRs to be generated to correct +the problems found. + +

Release

+ +When testing has been completed successfully a new distribution image is +created from the current CVS code "snapshot". No production release shall +contain software that has not passed the appropriate software tests. + + + +

Coding Requirements

+ +These coding requirements provide detailed information on source file +formatting and documentation content. These guidelines shall be applied +to all C and C++ source files provided with CUPS. + +

Source Files

+ +

Naming

+ +All source files names shall be 16 characters or less in length to +ensure compatibility with older UNIX filesystems. Source files +containing functions shall have an extension of ".c" for ANSI C and +".cxx" for C++ source files. All other "include" files shall have an +extension of ".h". + +

Documentation

+ +The top of each source file shall contain a header giving the name of the +file, the purpose or nature of the source file, the copyright and licensing +notice, and the functions contained in the file. The file name and revision +information is provided by the CVS "$Id$" tag: + +
    +
    +/*
    + * "$Id$"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-2001 by Easy Software Products, all rights
    + *   reserved.
    + *
    + *   These coded instructions, statements, and computer programs are
    + *   the property of Easy Software Products and are protected by
    + *   Federal copyright law.  Distribution and use rights are outlined
    + *   in the file "LICENSE.txt" which should have been included with
    + *   this file.  If this file is missing or damaged please contact
    + *   Easy Software Products at:
    + *
    + *       Attn: CUPS Licensing Information
    + *       Easy Software Products
    + *       44141 Airport View Drive, Suite 204
    + *       Hollywood, Maryland 20636-3111 USA
    + *
    + *       Voice: (301) 373-9600
    + *       EMail: cups-info@cups.org
    + *         WWW: http://www.cups.org
    + *
    + * Contents:
    + *
    + *   function1() - Description 1.
    + *   function2() - Description 2.
    + *   function3() - Description 3.
    + */
    +
    +
+ +The bottom of each source file shall contain a trailer giving the name +of the file using the CVS "$Id$" tag. The primary purpose of this is to +mark the end of a source file; if the trailer is missing it is possible +that code has been lost near the end of the file: + +
    +
    +/*
    + * End of "$Id$".
    + */
    +
    +
+ +

Functions

+ +

Naming

+ +Functions with a global scope shall be capitalized ("DoThis", "DoThat", +"DoSomethingElse", etc.) The only exception to this rule shall be the +CUPS interface library functions which may begin with a prefix word in +lowercase ("cupsDoThis", "cupsDoThat", etc.) + +

Functions with a local scope shall be declared "static" and be lowercase +with underscores between words ("do_this", "do_that", "do_something_else", +etc.) + +

Documentation

+ +Each function shall begin with a comment header describing what the function +does, the possible input limits (if any), and the possible output values +(if any), and any special information needed: + +
    +
    +/*
    + * 'do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +static float     /* O - Inverse power value, 0.0 <= y <= 1.1 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */
    +{
    +  ...
    +  return (y);
    +}
    +
    +
+ +

Methods

+ +

Naming

+ +Methods shall be in lowercase with underscores between words ("do_this", +"do_that", "do_something_else", etc.) + +

Documentation

+ +Each method shall begin with a comment header describing what the method +does, the possible input limits (if any), and the possible output values +(if any), and any special information needed: + +
    +
    +/*
    + * 'class::do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +float                   /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +class::do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    +  ...
    +  return (y);
    +}
    +
    +
+ +

Variables

+ +

Naming

+ +Variables with a global scope shall be capitalized ("ThisVariable", +"ThatVariable", "ThisStateVariable", etc.) The only exception to this +rule shall be the CUPS interface library global variables which must +begin with the prefix "cups" ("cupsThisVariable", "cupsThatVariable", +etc.) Global variables shall be replaced by function arguments whenever +possible. + +

Variables with a local scope shall be lowercase with underscores between +words ("this_variable", "that_variable", etc.) Any local variables shared +by functions within a source file shall be declared "static". + +

Documentation

+ +Each variable shall be declared on a separate line and shall be immediately +followed by a comment block describing the variable: + +
    +int this_variable;   /* The current state of this */
    +int that_variable;   /* The current state of that */
    +
+ +

Types

+ +

Naming

+ +All type names shall be lowercase with underscores between words and +"_t" appended to the end of the name ("this_type_t", "that_type_t", +etc.) + +

Documentation

+ +Each type shall have a comment block immediately before the typedef: + +
    +
    +/*
    + * This type is for CUPS foobar options.
    + */
    +typedef int cups_this_type_t;
    +
    +
+ +

Structures

+ +

Naming

+ +All structure names shall be lowercase with underscores between words and +"_str" appended to the end of the name ("this_struct_str", "that_struct_str", +etc.) + +

Documentation

+ +Each structure shall have a comment block immediately before the struct +and each member shall be documented in accordance with the variable naming +policy above: + +
    +
    +/*
    + * This structure is for CUPS foobar options.
    + */
    +struct cups_this_struct_str
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+ +

Classes

+ +

Naming

+ +All class names shall be lowercase with underscores between words +("this_class", "that_class", etc.) + +

Documentation

+ +Each class shall have a comment block immediately before the class +and each member shall be documented in accordance with the variable naming +policy above: + +
    +
    +/*
    + * This class is for CUPS foobar options.
    + */
    +class cups_this_class
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+ +

Constants

+ +

Naming

+ +All constant names shall be uppercase with underscored between words +("THIS_CONSTANT", "THAT_CONSTANT", etc.) Constants defined for the CUPS +interface library must begin with an uppercase prefix +("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.) + +

Typed enumerations shall be used whenever possible to allow for type +checking by the compiler. + +

Documentation

+ +Comment blocks shall immediately follow each constant: + +
    +
    +enum
    +{
    +  CUPS_THIS_TRAY,   /* This tray */
    +  CUPS_THAT_TRAY    /* That tray */
    +};
    +
    +
+ +

Code

+ +

Documentation

+ +All source code shall utilize block comments within functions to describe +the operations being performed by a group of statements: + +
    +
    +/*
    + * Clear the state array before we begin...
    + */
    +
    +for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +  array[i] = STATE_IDLE;
    +
    +/*
    + * Wait for state changes...
    + */
    +
    +do
    +{
    +  for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +    if (array[i] != STATE_IDLE)
    +      break;
    +
    +  if (i == (sizeof(array) / sizeof(array[0])))
    +    sleep(1);
    +} while (i == (sizeof(array) / sizeof(array[0])));
    +
    +
+ +

Style

+ +

Indentation

+ +All code blocks enclosed by brackets shall begin with the opening brace +on a new line. The code then follows starting on a new line after the brace +and is indented 2 spaces. The closing brace is then placed on a new line +following the code at the original indentation: + +
    +
    +{
    +  int i; /* Looping var */
    +
    + /*
    +  * Process foobar values from 0 to 999...
    +  */
    +
    +  for (i = 0; i < 1000; i ++)
    +  {
    +    do_this(i);
    +    do_that(i);
    +  }
    +}
    +
    +
+ +Single-line statements following "do", "else", "for", "if", and "while" +shall be indented 2 spaces as well. Blocks of code in a "switch" block +shall be indented 4 spaces after each "case" and "default" case: + +
    +
    +switch (array[i])
    +{
    +  case STATE_IDLE :
    +      do_this(i);
    +      do_that(i);
    +      break;
    +  default :
    +      do_nothing(i);
    +      break;
    +}
    +
    +
+ +

Spacing

+ +A space shall follow each reserved word ("if", "while", etc.) Spaces shall +not be inserted between a function name and the arguments in parenthesis. + +

Return Values

+ +Parenthesis shall surround values returned from a function using "return": + +
    +
    +return (STATE_IDLE);
    +
    +
+ +

Loops

+ +Whenever convenient loops should count downward to zero to improve program +performance: + +
    +
    +for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
    +  array[i] = STATE_IDLE;
    +
    +
+ +

Software Trouble Report Form

+ +
+ + + + + + + + + + + + + + + + + + + +
Summary of Problem:________________________________________
Problem Severity:__1=RFE +
__2=Documentation-Error +
__3=Unable-to-Print-a-File +
__4=Unable-to-Print-to-a-Printer +
__5=Unable-to-Print-at-All
Problem Scope:__1=Machine __2=Operating-System __3=All
Detailed Description of Problem:________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________
+ + + diff --git a/doc/cups.css b/doc/cups.css new file mode 100644 index 0000000000..9285a5b5ee --- /dev/null +++ b/doc/cups.css @@ -0,0 +1,4 @@ +H1 { font-family: sans-serif } +H2 { font-family: sans-serif } +TH { text-align: left } + diff --git a/doc/cupsdoc.css b/doc/cupsdoc.css new file mode 100644 index 0000000000..333f20144d --- /dev/null +++ b/doc/cupsdoc.css @@ -0,0 +1,9 @@ +H1 { font-family: sans-serif } +H2 { font-family: sans-serif } +H3 { font-family: sans-serif } +H4 { font-family: sans-serif } +H5 { font-family: sans-serif } +H6 { font-family: sans-serif } +SUP { font-family: sans-serif; font-size: 6pt } +PRE { margin-left: 2em } +CODE { font-weight: bold } diff --git a/doc/documentation.html b/doc/documentation.html new file mode 100644 index 0000000000..280fdb1434 --- /dev/null +++ b/doc/documentation.html @@ -0,0 +1,81 @@ + + + Documentation - Common UNIX Printing System + + + Easy Software Products Home Page + Do Administration Tasks + Manage Printer Classes Status + On-Line Help + Manage Jobs + Manage Printers + Download the Current CUPS Software + + + + +
+Common UNIX Printing System +
+ +

Documentation

+ +The following documentation for CUPS is available on this server: + +
    + +
  • Whitepaper - An Overview of the Common UNIX Printing System ( + HTML | + PDF ) + +
  • Software Users Manual ( + HTML | + PDF ) + +
  • Software Administrators Manual ( + HTML | + PDF ) + +
  • Software Programmers Manual ( + HTML | + PDF ) + +
  • Configuration Management Plan ( + HTML | + PDF ) + +
  • CUPS Implementation of IPP ( + HTML | + PDF ) + +
  • Interface Design Description ( + HTML | + PDF ) + +
  • Software Design Description ( + HTML | + PDF ) + +
  • Software Performance Specification ( + HTML | + PDF ) + +
  • Software Version Description ( + HTML | + PDF ) + +
  • Software Security Report ( + HTML | + PDF ) + +
+ +
+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-2001 by Easy Software Products, +All Rights Reserved. + + + diff --git a/doc/figures.sc b/doc/figures.sc new file mode 100644 index 0000000000000000000000000000000000000000..f51e814a63256737793741a4c9ffcd0c294da8b8 GIT binary patch literal 75144 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 + +

Terms

+ +
+ +
C +
A computer language. + +
parallel +
Sending or receiving data more than 1 bit at a time. + +
pipe +
A one-way communications channel between two programs. + +
serial +
Sending or receiving data 1 bit at a time. + +
socket +
A two-way network communications channel. + +
+ +

Acronyms

+ +
+ +
ASCII +
American Standard Code for Information Interchange + +
CUPS +
Common UNIX Printing System + +
ESC/P +
EPSON Standard Code for Printers + +
FTP +
File Transfer Protocol + +
HP-GL +
Hewlett-Packard Graphics Language + +
HP-PCL +
Hewlett-Packard Page Control Language + +
HP-PJL +
Hewlett-Packard Printer Job Language + +
IETF +
Internet Engineering Task Force + +
IPP +
Internet Printing Protocol + +
ISO +
International Standards Organization + +
LPD +
Line Printer Daemon + +
MIME +
Multimedia Internet Mail Exchange + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
diff --git a/doc/idd.html b/doc/idd.html new file mode 100644 index 0000000000..e8505391a0 --- /dev/null +++ b/doc/idd.html @@ -0,0 +1,1086 @@ + + + + CUPS Interface Design Description + + + + + + + +

+

CUPS Interface Design Description


+CUPS-IDD-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Internal Interfaces + +4 External Interfaces + +5 Directories +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+

This interface design description document provides detailed file +formats, message formats, and program conventions for the Common UNIX +Printing System ("CUPS") Version 1.1.

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This interface design description document is organized into the +following sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Internal Interfaces
  • +
  • 4 - External Interfaces
  • +
  • 5 - Directories
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Internal Interfaces

+

3.1 Character Set Files

+

The character set files define a mapping between 8-bit characters +and the Unicode character set, or between Unicode and printer fonts. +They are named using the IETF charset names defined in RFCnnnn. These +files are ASCII text, the content of which is described below. Comments +can be included by using the # character in the first column +of a line.

+

3.1.1 8-Bit Character Set Files

+

8-bit character set files start with a line reading:

+
    +
    +charset 8bit
    +
    +
+

Following this are lines that define the font information:

+
    +
    +first last direction width normal bold italic bold-italic
    +
    +
+

First and last are the first and last glyphs +in the font mapping that correspond to that font; a maximum of 256 +characters can be mapped within each group, with a maximum of 256 +mappings (this is a PostScript limitation.) The glyph values are +hexadecimal.

+

Direction is the string "ltor", "rtol", or "rtola" +indicating left-to-right, right-to-left, or right-to-left Arabic text.

+

Width is the string "single" or "double"; double means +that the glyphs are twice as wide as ASCII characters in the Courier +typeface.

+

Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only +available in a single style then only one typeface should be listed +(e.g. "Symbol".) Each font that is listed will be used (and downloaded +if needed) when printing.

+

The remaining lines define a character to Unicode glyph mapping for +the character set. The character and glyph values are hexadecimal:

+
    +
    +xx yyyy
    +
    +
+

3.1.2 Unicode Character Set Files

+

Unicode character set files start with a line reading:

+
    +
    +charset encoding
    +
    +
+

Encoding is the encoding to use for the text; currently +only the string "utf8" is supported.

+

Following this are lines defining the font information:

+
    +
    +first last direction width normal bold italic bold-italic
    +
    +
+

First and last are the first and last glyphs +in the font mapping that correspond to that font; a maximum of 256 +characters can be mapped within each group, with a maximum of 256 +mappings (this is a PostScript limitation.) The glyph values are +hexadecimal.

+

Direction is the string "ltor", "rtol", or "rtola" +indicating left-to-right, right-to-left, or right-to-left Arabic text.

+

Width is the string "single" or "double"; double means +that the glyphs are twice as wide as ASCII characters in the Courier +typeface.

+

Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only +available in a single style then only one typeface should be listed +(e.g. "Symbol".) Each font that is listed will be used (and downloaded +if needed) when printing.

+

3.2 Language Files

+

The language files define the default character set and a collection +of text messages in that language. They are named by prefixing the +string "cups_" to the front of the language specifier (e.g. "cups_en", +"cups_fr", etc.) Each file consists of two or more lines of ASCII text.

+

The first line identifies the character set to be used for the +messages. The currently recognized values are:

+
    +
  • iso-8859-1
  • +
  • iso-8859-2
  • +
  • iso-8859-3
  • +
  • iso-8859-4
  • +
  • iso-8859-5
  • +
  • iso-8859-6
  • +
  • iso-8859-7
  • +
  • iso-8859-8
  • +
  • iso-8859-9
  • +
  • iso-8859-10
  • +
  • iso-8859-13
  • +
  • iso-8859-14
  • +
  • iso-8859-15
  • +
  • us-ascii
  • +
  • utf-8
  • +
  • windows-874
  • +
  • windows-1250
  • +
  • windows-1251
  • +
  • windows-1252
  • +
  • windows-1253
  • +
  • windows-1254
  • +
  • windows-1255
  • +
  • windows-1256
  • +
  • windows-1257
  • +
  • windows-1258
  • +
+

The second and succeeding lines define text messages. If the message +text is preceded by a number, then the current message number is +updated and the text after the number is used.

+

3.3 MIME Files

+

CUPS uses two MIME files in its standard configuration.

+

3.3.1 mime.types

+

The mime.types file defines the recognized file types and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character. The backslash ("\") character can be used at the end +of a line to continue that line to the next.

+

Each non-blank line starts with a MIME type identifier +("super/type") as registered with the IANA. All text following the MIME +type is treated as a series of type recognition rules:

+
    +
    +mime-type := super "/" type { SP rule }*
    +super := { "a-z" | "A-Z" }*
    +type := { "a-z" | "A-Z" | "-" | "." | "0-9" }*
    +rule := { extension | match | operator | "(" rule ")" }*
    +extension := { "a-z" | "A-Z" | "0-9" }*
    +match := "match(" regexp ")" |
    +         "ascii(" offset "," length ")" |
    +	 "printable(" offset "," length ")" |
    +	 "string(" offset "," string ")" |
    +	 "contains(" offset "," length "," string ")" |
    +	 "char(" offset "," value ")" |
    +	 "short(" offset "," value ")" |
    +	 "int(" offset "," value ")" |
    +	 "locale(" string ")"
    +operator := "+" |	[ logical AND ]
    +            "," | SP    [ logical OR ]
    +	    "!"         [ unary NOT ]
    +
    +
+

The int and short rules match look for +integers in network byte order (a.k.a. big-endian) with the +most-significant byte first.

+

3.3.2 mime.convs

+

The mime.types file defines the recognized file filters and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character.

+

Each non-blank line starts with two MIME type identifiers +("super/type") representing the source and destination types. Following +the MIME types are a cost value (0 to 100) and the filter program to +use. If the filter program is not specified using the full path then it +must reside in the CUPS filter directory:

+
    +
    +super/type SP super/type2 SP cost SP program
    +
    +
+

3.4 Option Files

+

CUPS maintains user-defined printer and option files for each +printer and user on the system. The printers and options defined in the +system option file (/etc/cups/lpoptions) are loaded first, +followed by the user option file ($HOME/.lpoptions). +Options in the user file replace those defined in the system file for +the same destination. Each line in the files can be one of the +following:

+
    +
    +Dest name option=value option=value ... option=value
    +Dest name/instance option=value option=value ... option=value
    +Default name option=value option=value ... option=value
    +Default name/instance option=value option=value ... option=value
    +
    +
+

The line beginning with "Default" indicates the default destination +for print jobs; a default line in the user option file overrides the +default defined in the system option file.

+

Name is the name of a printer known to the local server.

+

Instance can be any string of letters, numbers, and the +underscore up to 127 characters in length.

+

The remainder of the line contains a list of space-separated options +and their values.

+

3.5 PostScript Printer Description Files

+

PostScript Printer Description ("PPD") files describe the +capabilities of each printer and are used by CUPS to support +printer-specific features and intelligent filtering.

+

3.5.1 PPD Specification

+

The PPD file format is described in + Adobe TechNote #5003: PostScript Printer Description File Format +Specification Version 4.3.

+

3.5.2 CUPS Extensions to PPD Files

+

CUPS adds several new attributes that are described below.

+

3.5.2.1 cupsFilter

+

This string attribute provides a conversion rule of the form:

+
    +
    +source/type cost program
    +
    +
+

The destination type is assumed to the printer's type. If a printer +supports the source type directly the special filter program "-" may be +specified.

+

3.5.2.2 cupsManualCopies

+

This boolean attribute notifies the RIP filters that the destination +printer does not support copy generation in hardware. The default value +is false.

+

3.5.2.3 cupsModelNumber

+

This integer attribute specifies a printer-specific model number. +This number can be used by a filter program to adjust the output for a +specific model of printer.

+

3.5.2.4 cupsProfile

+

This string attribute specifies a color profile of the form:

+
    +
    +resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
    +
    +
+

The resolution and type values may be "-" to act as a +wildcard. Otherwise they must match one of the Resolution + or MediaType attributes defined in the PPD file.

+

The density and gamma values define gamma and density +adjustment function such that:

+
    +
    +f(x) = density * xgamma
    +
    +
+

The m00 through m22 values define a 3x3 transformation +matrix for the CMY color values. The density function is applied +after the CMY transformation.

+

3.5.2.5 cupsVersion

+

This required attribute describes which version of the CUPS IDD was +used for the PPD file extensions. Currently it must be the string "1.0" +or "1.1".

+

3.6 Scheduler Configuration Files

+

The scheduler reads three configuration files that define the +available printers, classes, and services:

+
+
classes.conf
+
This file defines all of the printer classes known to the system.
+
cupsd.conf
+
This file defines the files, directories, passwords, etc. used by +the scheduler.
+
printers.conf
+
This file defines all of the printers known to the system.
+
+

3.6.1 classes.conf

+

The classes.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

+

Each non-blank line starts with the name of a configuration +directive followed by its value. The following directives are +understood: +

+ + + + + + + + + + + + + + +
DirectiveDescription
<Class name> +
</Class>
Surrounds a class definition.
<DefaultClass name> +
</Class>
Surrounds a class definition for the default +destination.
AcceptingSpecifies whether the class is accepting new +jobs. May be the names "Yes" or "No".
AllowUsersSpecifies a list of users that are allowed +to access the class.
BannerStartSpecifies the banner that is printed before +other files in a job.
BannerEndSpecifies the banner that is printed after +other files in a job.
DenyUsersSpecifies a list of users that are not +allowed to access the class.
InfoA textual description of the class.
LocationA textual location of the class.
PrinterSpecifies a printer that is a member of the +class.
StateSpecifies the initial state of the class; can be +"Idle" or "Stopped".
StateMessageSpecifies a textual message for the +current class state.
+
+

+

3.6.2 cupsd.conf

+

The cupsd.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

+

Each non-blank line starts with the name of a configuration +directive followed by its value. The following directives are +understood: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDefaultDescription
AccessLogaccess_logSpecifies the location of +the access log file. The special name "syslog" can be used to send +access log information to the system log.
Allow-Allows connections from the specified +host, network, or domain.
AuthClass-Specifies what level of +authentication is required; may be "User", "System", or "Group".
AuthTypeNoneSpecifies the type of +authentication to perform; may be "None", "Basic", or "Digest".
BrowseAddress255.255.255.255Specifies a +broadcast address to send CUPS browsing packets to.
BrowseAllow-Specifies hosts or addresses from +which browsing information should be used.
BrowseDeny-Specifies hosts or addresses from +which browsing information should not be used.
BrowseInterval30Specifies the number of +seconds between browsing updates. A browse interval of 0 seconds +disables outgoing packets.
BrowseOrderAllow,DenySpecifies the order of +BrowseAllow and BrowseDeny directive processing; can be "Deny,Allow" +to implicitly deny hosts unless they are allowed by a BrowseAllow +line, or "Allow,Deny" to implicitly allow hosts unless they are denied +by a BrowseDeny line.
BrowsePoll-Specifies a server to poll for +available printers and classes.
BrowsePort631Specifies the UDP port number to +use for browse packets.
BrowseRelay-Specifies a source and +destination address for relaying browser information from one subnet +to another.
BrowseShortNamesyesSpecifies whether or not +to provide short names (without the "@server" part) for remote +printers.
BrowseTimeout300Specifies the number of +seconds to wait until remote destinations are removed from the local +destination list.
BrowsingOnSpecifies whether or not printer +and class browsing is enabled; can be "On" or "Off".
DataDir/usr/share/cupsSpecifies the directory +where CUPS data files are stored.
DefaultCharsetiso-8859-1Specifies the default +character set.
DefaultLanguagecurrent localeSpecifies the +default language.
Deny-Refuses connections from the specified +host, network, or domain.
DocumentRoot/usr/share/doc/cupsSpecifies the +document data root directory.
ErrorLogerror_logSpecifies the error log file +location. The special name "syslog" can be used to send error log +information to the system log.
Grouproot, sys, systemSpecifies the group +name or ID that is used when running external programs.
HostNameLookupsOffSpecifies whether or not to +perform reverse IP address lookups to get the actual hostname; may be +"On" or "Off". Hostname lookups can significantly degrade the +performance of the CUPS server if one or more DNS servers is not +functioning properly.
ImplicitClassesOnSpecifies whether or not to +automatically create printer classes when more than one printer or +class of the same name is detected on the network; may be "On" or +"Off".
KeepAliveOnSpecifies whether or not to use +the HTTP Keep-Alive feature; may be "On" or "Off".
KeepAliveTimeout30Specifies the amount of +time to keep the HTTP connection alive before closing it.
<Location path> +
</Location>
-Specifies a location to restrict +access to.
LogLevelinfoControls the amount of +information that is logged in the error log file. Can be one of +"debug", "info", "warn", "error", or "none", in decreasing order or +verbosity.
MaxClients100Specifies the maximum number of +simultaneous active clients. This value is internally limited to 1/3 +of the total number of available file descriptors.
MaxLogSize0Specifies the maximum size of the +access, error, and page log files in bytes. If set to 0 then no +maximum size is set. Log files are rotated automatically when this +size is exceeded.
MaxRequestSize0Specifies the maximum size of +HTTP requests in bytes. If set to 0 then there is no maximum.
OrderAllow,DenySpecifies the order of Allow +and Deny directive processing; can be "Deny,Allow" to implicitly deny +hosts unless they are allowed by an Allow line, or "Allow,Deny" to +implicitly allow hosts unless they are denied by a Deny line.
PageLogpage_logSpecifies the location of the +page log file. The special name "syslog" can be used to send page log +information to the system log.
Port631Specifies a port number to listen to +for HTTP connections.
Printcap/etc/printcapSpecifies the location +of a Berkeley printcap file to update with a list of current printers +and classes. If no filename is supplied then this automatic generation +is disabled.
RequestRoot/var/spool/cupsSpecifies the +location of request files.
RIPCache8mSpecifies the size of the memory +cache in bytes that is used by RIP filters.
ServerAdminroot@ServerNameSpecifies the +person to contact with problems.
ServerNamehostnameSpecifies the hostname that +is supplied to HTTP clients. This is also used to determine the +default CUPS server for the CUPS IPP client applications.
ServerRoot/etc/cupsSpecifies the root +directory for server configuration files.
SystemGrouproot, sys, systemSpecifies the +group name used for System class authentication.
TempDir/var/tmpSpecifies the temporary +directory to use.
Timeout300The timeout in seconds before +client connections are closed in the middle of a request.
UserlpSpecifies the user that is used when +running external programs.
+
+

+

3.6.3 printers.conf

+

The printers.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

+

Each non-blank line starts with the name of a configuration +directive followed by its value. The following directives are +understood: +

+ + + + + + + + + + + + + + +
DirectiveDescription
AcceptingSpecifies whether the printer is accepting +new jobs. May be the names "Yes" or "No".
<DefaultPrinter name> +
</Printer>
Surrounds the printer definition for a default +destination.
AllowUsersSpecifies a list of users that are allowed +to access the printer.
BannerStartSpecifies the banner that is printed before +other files in a job.
BannerEndSpecifies the banner that is printed after +other files in a job.
DenyUsersSpecifies a list of users that are not +allowed to access the printer.
DeviceURISpecifies the device-uri attribute for the +printer.
InfoA textual description of the printer.
LocationA textual location of the printer.
<Printer name> +
</Printer>
Surrounds the printer definition.
StateSpecifies the initial state of the printer; can +be "Idle" or "Stopped".
StateMessageSpecifies a textual message for the +current printer state.
+
+

+

4 External Interfaces

+

4.1 AppSocket Protocol

+

The AppSocket protocol is an 8-bit clean TCP/IP socket connection. +The default IP service port is 9100. The URI method name is "socket".

+

The AppSocket protocol is used by the Hewlett Packard JetDirect +network interfaces and print servers, as well as many other vendors' +products. See the CUPS Software Administrators Manual for a list of +supported products.

+

4.2 CUPS Browsing Protocol

+

The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By +default this service operates on IP service port 631.

+

Each broadcast packet describes the state of a single printer or +class and is an ASCII text string of up to 1450 bytes ending with a +newline (0x0a). The string is formatted as follows:

+
    +
    +type SP state SP uri SP "location" SP "info" SP "make-and-model" NL
    +
    +
+

State, uri, location, info, and make-and-model +, correspond to the IPP printer-state, +printer-uri-supported, printer-location, +printer-info, and printer-make-and-model + attributes.

+

Type is a hexadecimal number string representing +capability/type bits: +

+ + + + + + + + + + + + + + + + + + +
BitDescription
00 = printer +
1 = class
10 = local +
1 = remote +
(always 1)
21 = can print B
31 = can print color
41 = can duplex
51 = can staple
61 = can do fast copies
71 = can do fast collating
81 = can punch holes
91 = can cover
101 = can bind
111 = can sort
121 = can print up to 9x14 inches
131 = can print up to 18x24 inches
141 = can print up to 36x48 inches
151 = can print variable sizes
+
+

+

4.3 CUPS Form File

+

CUPS Form files are XML files used by the CUPS formtops + filter to produce dynamic banner pages and support preprinted forms.

+

The MIME type for CUPS Form files is application/vnd.cups-form +.

+

4.3.1 CUPS Form DTD

+

The following DTD describes the available elements and attributes in +a CUPS Form file: +

+ + +
+
+<!ENTITY % Angle "CDATA" -- angle in degrees -->
+
+<!ENTITY % Color "CDATA" -- a color using sRGB: #RRGGBB as Hex values -->
+
+<!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % Lengths "CDATA" -- comma-separated Length values -->
+
+<!ENTITY % Text "CDATA">
+
+<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
+
+<!ENTITY % preformatted "PRE">
+
+<!ENTITY % i18n
+ "lang        %LanguageCode; #IMPLIED  -- language code --
+  dir         (ltr|rtl)      #IMPLIED  -- direction for weak/neutral text --"
+  >
+
+<!ENTITY % attrs "%i18n;">
+
+<!ENTITY % fontstyle
+ "B | FONT | I | TT">
+
+<!ENTITY % graphics
+ "BOX | RECT | LINE | POLY | ARC | PIE | TEXT">
+
+<!ENTITY % insert
+ "IMG | VAR">
+
+<!-- %inline; covers inline or "text-level" elements -->
+<!ENTITY % inline "#PCDATA | %fontstyle; | %graphics; | %insert;">
+
+<!ELEMENT (%fontstyle;) - - (%inline;)*>
+<!ATTLIST (%fontstyle;)
+  %attrs;                              -- %i18n --
+  >
+
+<!ELEMENT BR - O EMPTY                 -- forced line break -->
+<!ATTLIST BR
+  %attrs;                              -- %i18n --
+  >
+
+<!ENTITY % block
+     "P | %heading; | %preformatted;">
+
+<!ENTITY % flow "%block; | %inline;">
+
+<!ELEMENT PAGE O O (%flow;)+           -- document body -->
+<!ATTLIST PAGE
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+  >
+
+<!ELEMENT P - O (%inline;)*            -- paragraph -->
+<!ATTLIST P
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT (%heading;)  - - (%inline;)* -- heading -->
+<!ATTLIST (%heading;)
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT PRE - - (%inline;)*          -- preformatted text -->
+<!ATTLIST PRE
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT BOX - O EMPTY                -- unfilled box -->
+<!ATTLIST BOX
+  color       %Color;        #IMPLIED  -- override color --
+  height      %Length;       #REQUIRED -- height of box --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT RECT - O EMPTY               -- filled box -->
+<!ATTLIST RECT
+  color       %Color;        #IMPLIED  -- override color --
+  height      %Length;       #REQUIRED -- height of box --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT LINE - O EMPTY               -- polyline -->
+<!ATTLIST LINE
+  color       %Color;        #IMPLIED  -- override color --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  x           %Lengths;      #REQUIRED -- horizontal positions --
+  y           %Lengths;      #REQUIRED -- vertical positions --
+  >
+
+<!ELEMENT POLY - O EMPTY               -- polygon (filled) -->
+<!ATTLIST POLY
+  color       %Color;        #IMPLIED  -- override color --
+  x           %Lengths;      #REQUIRED -- horizontal positions --
+  y           %Lengths;      #REQUIRED -- vertical positions --
+  >
+
+<!ELEMENT ARC - O EMPTY                -- unfilled arc -->
+<!ATTLIST ARC
+  color       %Color;        #IMPLIED  -- override color --
+  end         %Angle;        #IMPLIED  -- override end angle --
+  height      %Length;       #REQUIRED -- height of arc --
+  start       %Angle;        #IMPLIED  -- override start angle --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  width       %Length;       #REQUIRED -- width of arc --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT PIE - O EMPTY                -- filled arc -->
+<!ATTLIST PIE
+  color       %Color;        #IMPLIED  -- override color --
+  end         %Angle;        #IMPLIED  -- override end angle --
+  height      %Length;       #REQUIRED -- height of arc --
+  start       %Angle;        #IMPLIED  -- override start angle --
+  width       %Length;       #REQUIRED -- width of arc --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT TEXT - - (%flow;)*           -- text box -->
+<!ATTLIST RECT
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  height      %Length;       #REQUIRED -- height of box --
+  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+
+<!ELEMENT IMG - O EMPTY                -- Embedded image -->
+<!ATTLIST IMG
+  %attrs;                              -- %coreattrs, %i18n, %events --
+  src         %URI;          #REQUIRED -- URI of image to embed --
+  height      %Length;       #IMPLIED  -- override height --
+  width       %Length;       #IMPLIED  -- override width --
+  >
+
+<!ELEMENT HEAD O O (DEFVAR)*           -- document head -->
+<!ATTLIST HEAD
+  %i18n;                               -- lang, dir --
+  >
+
+<!ELEMENT DEFVAR - O EMPTY             -- variable definition -->
+<!ATTLIST DEFVAR
+  name        CDATA          #REQUIRED -- name
+  value       CDATA          #REQUIRED -- value
+  >
+
+
+<!ENTITY % html.content "HEAD, PAGE">
+
+<!ELEMENT CUPSFORM - - (HEAD) (PAGE)+  -- document root element -->
+<!ATTLIST CUPSFORM
+  %i18n;                               -- lang, dir --
+  >
+
+
+
+

+

4.4 CUPS PostScript File

+

CUPS PostScript files are device-dependent Adobe PostScript program +files. The PostScript language is described in the + Adobe PostScript Language Reference Manual, Third Edition.

+

The MIME type for CUPS PostScript files is +application/vnd.cups-postscript.

+

4.5 CUPS Raster File

+

CUPS raster files are device-dependent raster image files that +contain a PostScript page device dictionary and device-dependent raster +imagery for each page in the document. These files are used to transfer +raster data from the PostScript and image file RIPs to device-dependent +filters that convert the raster data to a printable format.

+

A raster file begins with a four byte synchronization word: +0x52615374 ("RaSt") for big-endian architectures and 0x74536152 +("tSaR") for little-endian architectures. The writer of the raster +file will use the native word order, and the reader is responsible for +detecting a reversed word order file and swapping bytes as needed. The +CUPS Image Library raster functions perform this function +automatically.

+

Following the synchronization word are a series of raster pages. + Each page starts with a page device dictionary header and is followed +immediately by the raster data for that page. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BytesDescriptionValues
0-63MediaClassNul-terminated ASCII string
64-127MediaColorNul-terminated ASCII string
128-191MediaTypeNul-terminated ASCII string
192-255OutputTypeNul-terminated ASCII string
256-259AdvanceDistance0 to 232 - 1 +points
260-263AdvanceMedia0 = Never advance roll +
1 = Advance roll after file +
2 = Advance roll after job +
3 = Advance roll after set +
4 = Advance roll after page
264-267Collate0 = do not collate copies +
1 = collate copies
268-271CutMedia0 = Never cut media +
1 = Cut roll after file +
2 = Cut roll after job +
3 = Cut roll after set +
4 = Cut roll after page
272-275Duplex0 = Print single-sided +
1 = Print double-sided
276-283HWResolutionHorizontal and vertical +resolution in dots-per-inch.
284-299ImagingBoundingBoxFour integers giving +the left, bottom, right, and top positions of the page bounding box in +points
300-303InsertSheet0 = Do not insert separator +sheets +
1 = Insert separator sheets
304-307Jog0 = Do no jog pages +
1 = Jog pages after file +
2 = Jog pages after job +
3 = Jog pages after set
308-311LeadingEdge0 = Top edge is first +
1 = Right edge is first +
2 = Bottom edge is first +
3 = Left edge is first
312-319MarginsLeft and bottom origin of image +in points
320-323ManualFeed0 = Do not manually feed +media +
1 = Manually feed media
324-327MediaPositionInput slot position from +0 to N
328-331MediaWeightMedia weight in grams per +meter squared
332-335MirrorPrint0 = Do not mirror prints +
1 = Mirror prints
336-339NegativePrint0 = Do not invert prints +
1 = Invert prints
340-343NumCopies1 to 232 - 1
344-347Orientation0 = Do not rotate page +
1 = Rotate page counter-clockwise +
2 = Turn page upside down +
3 = Rotate page clockwise
348-351OutputFaceUp0 = Output face down +
1 = Output face up
352-359PageSizeWidth and length in points
360-363Separations0 = Print composite image +
1 = Print color separations
364-367TraySwitch0 = Do not change trays if +selected tray is empty +
1 = Change trays if selected tray is empty
368-371Tumble0 = Do not rotate even pages +when duplexing +
1 = Rotate even pages when duplexing
372-375cupsWidthWidth of page image in pixels
376-379cupsHeightHeight of page image in +pixels
380-383cupsMediaTypeDriver-specific 0 to 2 +32 - 1
384-387cupsBitsPerColor1, 2, 4, 8 bits
388-391cupsBitsPerPixel1 to 32 bits
392-395cupsBytesPerLine1 to 232 - +1 bytes
396-399cupsColorOrder0 = chunky pixels (CMYK +CMYK CMYK) +
1 = banded pixels (CCC MMM YYY KKK) +
2 = planar pixels (CCC... MMM... YYY... KKK...)
400-403cupsColorSpace0 = white +
1 = RGB +
2 = RGBA +
3 = black +
4 = CMY +
5 = YMC +
6 = CMYK +
7 = YMCK +
8 = KCMY +
9 = KCMYcm
404-407cupsCompressionDriver-specific 0 to 2 +32 - 1
408-411cupsRowCountDriver-specific 0 to 2 +32 - 1
412-415cupsRowFeedDriver-specific 0 to 2 +32 - 1
416-419cupsRowStepDriver-specific 0 to 2 +32 - 1
+
+

+

The MIME type for CUPS Raster files is +application/vnd.cups-raster.

+

4.6 CUPS Raw Files

+

Raw files are printer-dependent print files that are in a format +suitable to the destination printer (e.g. HP-PCL, HP-RTL, etc.) The +MIME type for CUPS Raw files is application/vnd.cups-raw.

+

4.7 Internet Printing Protocol

+

The Internet Printing Protocol and the CUPS extensions to it are +described in the CUPS Implementation of IPP document.

+

4.8 Line Printer Daemon Protocol

+

The Line Printer Daemon (LPD) protocol is described by +RFC 1179: Line Printer Daemon Protocol.

+

The URI method name for LPD is "lpd".

+

4.9 Server Message Block Protocol

+

The Server Message Block (SMB) and related Common Internet File +System (CIFS) protocols are described at +http://anu.samba.org/cifs.

+

The URI method name for SMB is "smb". Support for this protocol is +provided via the SAMBA smbspool(1) program provided with +SAMBA 2.0.6 and higher.

+

5 Directories

+
+
/etc/cups
+
The scheduler configuration and MIME files reside here.
+
/etc/cups/certs
+
The authentication certificates reside here.
+
/etc/cups/interfaces
+
System V interface scripts reside here.
+
/etc/cups/ppd
+
This directory contains PPD files for each printer.
+
/usr/bin
+
The cancel, lp, lpq, + lpr, lprm, and lpstat commands + reside here.
+
/usr/lib, /usr/lib32
+
The shared libraries (DSOs) reside here.
+
/usr/lib/cups/backend
+
The backend filters reside here.
+
/usr/lib/cups/cgi-bin
+
The CGI programs reside here.
+
/usr/lib/cups/daemon
+
The polling and LPD daemons reside here.
+
/usr/lib/cups/filter
+
The file filters reside here.
+
/usr/sbin
+
The accept, cupsd, lpadmin, +lpc, and reject commands reside here.
+
/usr/share/cups
+
This is the root directory of the CUPS static data.
+
/usr/share/cups/charsets
+
The character set files reside here.
+
/usr/share/cups/data
+
The filter data files reside here.
+
/usr/share/cups/fonts
+
The pstoraster font files reside here.
+
/usr/share/cups/model
+
The sample PPD files reside here.
+
/usr/share/cups/pstoraster
+
The pstoraster data files reside here.
+
/usr/share/doc/cups
+
The scheduler documentation files reside here.
+
/var/log/cups
+
The access_log, error_log, and + page_log files reside here.
+
/var/spool/cups
+
This directory contains print job files.
+
+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/idd.pdf b/doc/idd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8857c0288f6f6766f4a03250e278099006d430ce GIT binary patch literal 68356 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 + + + + + CUPS Interface Design Description + + + +

Scope

+ +

Identification

+ +

This interface design description document provides detailed file +formats, message formats, and program conventions for the Common UNIX +Printing System ("CUPS") Version 1.1. + + + +

Document Overview

+ +

This interface design description document is organized into the following +sections: + +

    +
  • 1 - Scope +
  • 2 - References +
  • 3 - Internal Interfaces +
  • 4 - External Interfaces +
  • 5 - Directories +
  • A - Glossary +
+ + + +

Internal Interfaces

+ +

Character Set Files

+ +

The character set files define a mapping between 8-bit characters +and the Unicode character set, or between Unicode and printer fonts. +They are named using the IETF charset names defined in RFCnnnn. These +files are ASCII text, the content of which is described below. Comments +can be included by using the # character in the first column +of a line. + +

8-Bit Character Set Files

+ +

8-bit character set files start with a line reading: + +

    +charset 8bit
    +
+ +

Following this are lines that define the font information: + +

    +first last direction width normal bold italic bold-italic
    +
+ +

First and last are the first and last glyphs +in the font mapping that correspond to that font; a maximum of 256 +characters can be mapped within each group, with a maximum of 256 +mappings (this is a PostScript limitation.) The glyph values are +hexadecimal. + +

Direction is the string "ltor", "rtol", or "rtola" indicating +left-to-right, right-to-left, or right-to-left Arabic text. + +

Width is the string "single" or "double"; double means that the +glyphs are twice as wide as ASCII characters in the Courier typeface. + +

Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only available in +a single style then only one typeface should be listed (e.g. "Symbol".) +Each font that is listed will be used (and downloaded if needed) when +printing. + +

The remaining lines define a character to Unicode glyph mapping for the +character set. The character and glyph values are hexadecimal: + +

    +xx yyyy
    +
+ +

Unicode Character Set Files

+ +

Unicode character set files start with a line reading: + +

    +charset encoding
    +
+ +

Encoding is the encoding to use for the text; currently only +the string "utf8" is supported. + +

Following this are lines defining the font information: + +

    +first last direction width normal bold italic bold-italic
    +
+ +

First and last are the first and last glyphs +in the font mapping that correspond to that font; a maximum of 256 +characters can be mapped within each group, with a maximum of 256 +mappings (this is a PostScript limitation.) The glyph values are +hexadecimal. + +

Direction is the string "ltor", "rtol", or "rtola" indicating +left-to-right, right-to-left, or right-to-left Arabic text. + +

Width is the string "single" or "double"; double means that the +glyphs are twice as wide as ASCII characters in the Courier typeface. + +

Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only available in +a single style then only one typeface should be listed (e.g. "Symbol".) +Each font that is listed will be used (and downloaded if needed) when +printing. + +

Language Files

+ +

The language files define the default character set and a collection of +text messages in that language. They are named by prefixing the string "cups_" +to the front of the language specifier (e.g. "cups_en", "cups_fr", etc.) Each +file consists of two or more lines of ASCII text. + +

The first line identifies the character set to be used for the messages. +The currently recognized values are: + +

    +
  • iso-8859-1 +
  • iso-8859-2 +
  • iso-8859-3 +
  • iso-8859-4 +
  • iso-8859-5 +
  • iso-8859-6 +
  • iso-8859-7 +
  • iso-8859-8 +
  • iso-8859-9 +
  • iso-8859-10 +
  • iso-8859-13 +
  • iso-8859-14 +
  • iso-8859-15 +
  • us-ascii +
  • utf-8 +
  • windows-874 +
  • windows-1250 +
  • windows-1251 +
  • windows-1252 +
  • windows-1253 +
  • windows-1254 +
  • windows-1255 +
  • windows-1256 +
  • windows-1257 +
  • windows-1258 +
+ +

The second and succeeding lines define text messages. If the message text +is preceded by a number, then the current message number is updated and the +text after the number is used. + +

MIME Files

+ +

CUPS uses two MIME files in its standard configuration. + +

mime.types

+ +

The mime.types file defines the recognized file types and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character. The backslash ("\") character can be used at the end +of a line to continue that line to the next. + +

Each non-blank line starts with a MIME type identifier ("super/type") +as registered with the IANA. All text following the MIME type is treated as +a series of type recognition rules: + +

    +mime-type := super "/" type { SP rule }*
    +super := { "a-z" | "A-Z" }*
    +type := { "a-z" | "A-Z" | "-" | "." | "0-9" }*
    +rule := { extension | match | operator | "(" rule ")" }*
    +extension := { "a-z" | "A-Z" | "0-9" }*
    +match := "match(" regexp ")" |
    +         "ascii(" offset "," length ")" |
    +	 "printable(" offset "," length ")" |
    +	 "string(" offset "," string ")" |
    +	 "contains(" offset "," length "," string ")" |
    +	 "char(" offset "," value ")" |
    +	 "short(" offset "," value ")" |
    +	 "int(" offset "," value ")" |
    +	 "locale(" string ")"
    +operator := "+" |	[ logical AND ]
    +            "," | SP    [ logical OR ]
    +	    "!"         [ unary NOT ]
    +
+ +

The int and short rules match look for integers +in network byte order (a.k.a. big-endian) with the most-significant byte first. + +

mime.convs

+ +

The mime.types file defines the recognized file filters and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character. + +

Each non-blank line starts with two MIME type identifiers ("super/type") +representing the source and destination types. Following the MIME types are +a cost value (0 to 100) and the filter program to use. If the filter program +is not specified using the full path then it must reside in the CUPS filter +directory: + +

    +super/type SP super/type2 SP cost SP program
    +
+ +

Option Files

+ +

CUPS maintains user-defined printer and option files for each +printer and user on the system. The printers and options defined in the +system option file (/etc/cups/lpoptions) are loaded first, +followed by the user option file ($HOME/.lpoptions). +Options in the user file replace those defined in the system file for +the same destination. Each line in the files can be one of the +following: + +

    +Dest name option=value option=value ... option=value
    +Dest name/instance option=value option=value ... option=value
    +Default name option=value option=value ... option=value
    +Default name/instance option=value option=value ... option=value
    +
+ +

The line beginning with "Default" indicates the default destination for +print jobs; a default line in the user option file overrides the default +defined in the system option file. + +

Name is the name of a printer known to the local server. + +

Instance can be any string of letters, numbers, and the underscore +up to 127 characters in length. + +

The remainder of the line contains a list of space-separated options +and their values. + +

PostScript Printer Description Files

+ +

PostScript Printer Description ("PPD") files describe the capabilities +of each printer and are used by CUPS to support printer-specific features +and intelligent filtering. + +

PPD Specification

+ +

The PPD file format is described in + +Adobe TechNote #5003: PostScript Printer Description File Format +Specification Version 4.3. + +

CUPS Extensions to PPD Files

+ +

CUPS adds several new attributes that are described below. + +

cupsFilter

+ +

This string attribute provides a conversion rule of the form: + +

    +source/type cost program
    +
+ +

The destination type is assumed to the printer's type. If a printer +supports the source type directly the special filter program "-" may be +specified. + +

cupsManualCopies

+ +

This boolean attribute notifies the RIP filters that the destination printer +does not support copy generation in hardware. The default value is false. + +

cupsModelNumber

+ +

This integer attribute specifies a printer-specific model number. This number +can be used by a filter program to adjust the output for a specific model of +printer. + +

cupsProfile

+ +

This string attribute specifies a color profile of the form: + +

    +resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
    +
+ +

The resolution and type values may be "-" to act as a +wildcard. Otherwise they must match one of the Resolution or +MediaType attributes defined in the PPD file. + +

The density and gamma values define gamma and density +adjustment function such that: + +

    +f(x) = density * xgamma
    +
+ +

The m00 through m22 values define a 3x3 transformation +matrix for the CMY color values. The density function is applied after +the CMY transformation. + +

cupsVersion

+ +

This required attribute describes which version of the CUPS IDD was used +for the PPD file extensions. Currently it must be the string "1.0" or "1.1". + +

Scheduler Configuration Files

+ +

The scheduler reads three configuration files that define the available +printers, classes, and services: + +

+ +
classes.conf +
This file defines all of the printer classes known to the + system. + +
cupsd.conf +
This file defines the files, directories, passwords, etc. + used by the scheduler. + +
printers.conf +
This file defines all of the printers known to the system. + +
+ +

classes.conf

+ +

The classes.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDescription
<Class name>
+ </Class>
Surrounds a class definition.
<DefaultClass name>
+ </Class>
Surrounds a class definition for the default destination.
AcceptingSpecifies whether the class is accepting new jobs. May be + the names "Yes" or "No".
AllowUsersSpecifies a list of users that are allowed to access the class.
BannerStartSpecifies the banner that is printed before other files in a + job.
BannerEndSpecifies the banner that is printed after other files in a + job.
DenyUsersSpecifies a list of users that are not allowed to access the + class.
InfoA textual description of the class.
LocationA textual location of the class.
PrinterSpecifies a printer that is a member of the class.
StateSpecifies the initial state of the class; can be "Idle" or + "Stopped".
StateMessageSpecifies a textual message for the current class state.
+ +

cupsd.conf

+ +

The cupsd.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDefaultDescription
AccessLogaccess_logSpecifies the location of the access log file. The special name + "syslog" can be used to send access log information to the system + log.
Allow-Allows connections from the specified host, network, or + domain.
AuthClass-Specifies what level of authentication is required; may be + "User", "System", or "Group".
AuthTypeNoneSpecifies the type of authentication to perform; may be + "None", "Basic", or "Digest".
BrowseAddress255.255.255.255Specifies a broadcast address to send CUPS browsing packets to.
BrowseAllow-Specifies hosts or addresses from which browsing information + should be used.
BrowseDeny-Specifies hosts or addresses from which browsing information + should not be used.
BrowseInterval30Specifies the number of seconds between browsing updates. A + browse interval of 0 seconds disables outgoing packets.
BrowseOrderAllow,DenySpecifies the order of BrowseAllow and BrowseDeny directive + processing; can be "Deny,Allow" to implicitly deny hosts unless + they are allowed by a BrowseAllow line, or "Allow,Deny" to + implicitly allow hosts unless they are denied by a BrowseDeny + line.
BrowsePoll-Specifies a server to poll for available printers and classes.
BrowsePort631Specifies the UDP port number to use for browse packets.
BrowseRelay-Specifies a source and destination address for relaying browser + information from one subnet to another.
BrowseShortNamesyesSpecifies whether or not to provide short names (without the + "@server" part) for remote printers.
BrowseTimeout300Specifies the number of seconds to wait until remote destinations + are removed from the local destination list.
BrowsingOnSpecifies whether or not printer and class browsing is enabled; can + be "On" or "Off".
DataDir/usr/share/cupsSpecifies the directory where CUPS data files are stored.
DefaultCharsetiso-8859-1Specifies the default character set.
DefaultLanguagecurrent localeSpecifies the default language.
Deny-Refuses connections from the specified host, network, or + domain.
DocumentRoot/usr/share/doc/cupsSpecifies the document data root directory.
ErrorLogerror_logSpecifies the error log file location. The special name + "syslog" can be used to send error log information to the system + log.
Grouproot, sys, systemSpecifies the group name or ID that is used when running + external programs.
HostNameLookupsOffSpecifies whether or not to perform reverse IP address lookups to + get the actual hostname; may be "On" or "Off". Hostname lookups can + significantly degrade the performance of the CUPS server if one or + more DNS servers is not functioning properly.
ImplicitClassesOnSpecifies whether or not to automatically create printer classes + when more than one printer or class of the same name is detected on + the network; may be "On" or "Off".
KeepAliveOnSpecifies whether or not to use the HTTP Keep-Alive feature; may + be "On" or "Off".
KeepAliveTimeout30Specifies the amount of time to keep the HTTP connection alive + before closing it.
<Location path>
+ </Location>
-Specifies a location to restrict access to.
LogLevelinfoControls the amount of information that is logged in the + error log file. Can be one of "debug", "info", "warn", "error", + or "none", in decreasing order or verbosity.
MaxClients100Specifies the maximum number of simultaneous active clients. + This value is internally limited to 1/3 of the total number of + available file descriptors.
MaxLogSize0Specifies the maximum size of the access, error, and page + log files in bytes. If set to 0 then no maximum size is set. + Log files are rotated automatically when this size is + exceeded.
MaxRequestSize0Specifies the maximum size of HTTP requests in bytes. If set to 0 + then there is no maximum.
OrderAllow,DenySpecifies the order of Allow and Deny directive processing; can + be "Deny,Allow" to implicitly deny hosts unless they are allowed by + an Allow line, or "Allow,Deny" to implicitly allow hosts unless they + are denied by a Deny line.
PageLogpage_logSpecifies the location of the page log file. The special name + "syslog" can be used to send page log information to the system + log.
Port631Specifies a port number to listen to for HTTP connections.
Printcap/etc/printcapSpecifies the location of a Berkeley printcap file to update + with a list of current printers and classes. If no filename is + supplied then this automatic generation is disabled.
RequestRoot/var/spool/cupsSpecifies the location of request files.
RIPCache8mSpecifies the size of the memory cache in bytes that is used by + RIP filters.
ServerAdminroot@ServerNameSpecifies the person to contact with problems.
ServerNamehostnameSpecifies the hostname that is supplied to HTTP clients. This + is also used to determine the default CUPS server for the CUPS IPP + client applications.
ServerRoot/etc/cupsSpecifies the root directory for server configuration files.
SystemGrouproot, sys, systemSpecifies the group name used for System class authentication.
TempDir/var/tmpSpecifies the temporary directory to use.
Timeout300The timeout in seconds before client connections are closed + in the middle of a request.
UserlpSpecifies the user that is used when running external programs.
+ +

printers.conf

+ +

The printers.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDescription
AcceptingSpecifies whether the printer is accepting new jobs. May be + the names "Yes" or "No".
<DefaultPrinter name>
+ </Printer>
Surrounds the printer definition for a default destination.
AllowUsersSpecifies a list of users that are allowed to access the printer.
BannerStartSpecifies the banner that is printed before other files in a + job.
BannerEndSpecifies the banner that is printed after other files in a + job.
DenyUsersSpecifies a list of users that are not allowed to access the + printer.
DeviceURISpecifies the device-uri attribute for the printer.
InfoA textual description of the printer.
LocationA textual location of the printer.
<Printer name>
+ </Printer>
Surrounds the printer definition.
StateSpecifies the initial state of the printer; can be "Idle" or + "Stopped".
StateMessageSpecifies a textual message for the current printer state.
+ +

External Interfaces

+ +

AppSocket Protocol

+ +

The AppSocket protocol is an 8-bit clean TCP/IP socket connection. +The default IP service port is 9100. The URI method name is "socket". + +

The AppSocket protocol is used by the Hewlett Packard JetDirect +network interfaces and print servers, as well as many other vendors' +products. See the CUPS Software Administrators Manual for a list of +supported products. + +

CUPS Browsing Protocol

+ +

The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By default +this service operates on IP service port 631. + +

Each broadcast packet describes the state of a single printer or class and +is an ASCII text string of up to 1450 bytes ending with a newline (0x0a). The +string is formatted as follows: + +

    +type SP state SP uri SP "location" SP "info" SP "make-and-model" NL
    +
+ +

State, uri, location, info, and make-and-model, +correspond to the IPP printer-state, +printer-uri-supported, printer-location, +printer-info, and printer-make-and-model +attributes. + +

Type is a hexadecimal number string representing +capability/type bits: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
00 = printer
+ 1 = class
10 = local
+ 1 = remote
+ (always 1)
21 = can print B&W
31 = can print color
41 = can duplex
51 = can staple
61 = can do fast copies
71 = can do fast collating
81 = can punch holes
91 = can cover
101 = can bind
111 = can sort
121 = can print up to 9x14 inches
131 = can print up to 18x24 inches
141 = can print up to 36x48 inches
151 = can print variable sizes
+ +

CUPS Form File

+ +

CUPS Form files are XML files used by the CUPS formtops +filter to produce dynamic banner pages and support preprinted forms. + +

The MIME type for CUPS Form files is +application/vnd.cups-form. + +

CUPS Form DTD

+ +

The following DTD describes the available elements and attributes in +a CUPS Form file: + +

+ + + +
+<!ENTITY % Angle "CDATA" -- angle in degrees -->
+
+<!ENTITY % Color "CDATA" -- a color using sRGB: #RRGGBB as Hex values -->
+
+<!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % Lengths "CDATA" -- comma-separated Length values -->
+
+<!ENTITY % Text "CDATA">
+
+<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
+
+<!ENTITY % preformatted "PRE">
+
+<!ENTITY % i18n
+ "lang        %LanguageCode; #IMPLIED  -- language code --
+  dir         (ltr|rtl)      #IMPLIED  -- direction for weak/neutral text --"
+  >
+
+<!ENTITY % attrs "%i18n;">
+
+<!ENTITY % fontstyle
+ "B | FONT | I | TT">
+
+<!ENTITY % graphics
+ "BOX | RECT | LINE | POLY | ARC | PIE | TEXT">
+
+<!ENTITY % insert
+ "IMG | VAR">
+
+<!-- %inline; covers inline or "text-level" elements -->
+<!ENTITY % inline "#PCDATA | %fontstyle; | %graphics; | %insert;">
+
+<!ELEMENT (%fontstyle;) - - (%inline;)*>
+<!ATTLIST (%fontstyle;)
+  %attrs;                              -- %i18n --
+  >
+
+<!ELEMENT BR - O EMPTY                 -- forced line break -->
+<!ATTLIST BR
+  %attrs;                              -- %i18n --
+  >
+
+<!ENTITY % block
+     "P | %heading; | %preformatted;">
+
+<!ENTITY % flow "%block; | %inline;">
+
+<!ELEMENT PAGE O O (%flow;)+           -- document body -->
+<!ATTLIST PAGE
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+  >
+
+<!ELEMENT P - O (%inline;)*            -- paragraph -->
+<!ATTLIST P
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT (%heading;)  - - (%inline;)* -- heading -->
+<!ATTLIST (%heading;)
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT PRE - - (%inline;)*          -- preformatted text -->
+<!ATTLIST PRE
+  %attrs;                              -- %i18n --
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  >
+
+<!ELEMENT BOX - O EMPTY                -- unfilled box -->
+<!ATTLIST BOX
+  color       %Color;        #IMPLIED  -- override color --
+  height      %Length;       #REQUIRED -- height of box --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT RECT - O EMPTY               -- filled box -->
+<!ATTLIST RECT
+  color       %Color;        #IMPLIED  -- override color --
+  height      %Length;       #REQUIRED -- height of box --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT LINE - O EMPTY               -- polyline -->
+<!ATTLIST LINE
+  color       %Color;        #IMPLIED  -- override color --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  x           %Lengths;      #REQUIRED -- horizontal positions --
+  y           %Lengths;      #REQUIRED -- vertical positions --
+  >
+
+<!ELEMENT POLY - O EMPTY               -- polygon (filled) -->
+<!ATTLIST POLY
+  color       %Color;        #IMPLIED  -- override color --
+  x           %Lengths;      #REQUIRED -- horizontal positions --
+  y           %Lengths;      #REQUIRED -- vertical positions --
+  >
+
+<!ELEMENT ARC - O EMPTY                -- unfilled arc -->
+<!ATTLIST ARC
+  color       %Color;        #IMPLIED  -- override color --
+  end         %Angle;        #IMPLIED  -- override end angle --
+  height      %Length;       #REQUIRED -- height of arc --
+  start       %Angle;        #IMPLIED  -- override start angle --
+  thickness   %Length;       #IMPLIED  -- override line thickness --
+  width       %Length;       #REQUIRED -- width of arc --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT PIE - O EMPTY                -- filled arc -->
+<!ATTLIST PIE
+  color       %Color;        #IMPLIED  -- override color --
+  end         %Angle;        #IMPLIED  -- override end angle --
+  height      %Length;       #REQUIRED -- height of arc --
+  start       %Angle;        #IMPLIED  -- override start angle --
+  width       %Length;       #REQUIRED -- width of arc --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+<!ELEMENT TEXT - - (%flow;)*           -- text box -->
+<!ATTLIST RECT
+  align       (left|center|right) #IMPLIED -- horizontal alignment --
+  height      %Length;       #REQUIRED -- height of box --
+  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+  width       %Length;       #REQUIRED -- width of box --
+  x           %Length;       #REQUIRED -- horizontal position --
+  y           %Length;       #REQUIRED -- vertical position --
+  >
+
+
+<!ELEMENT IMG - O EMPTY                -- Embedded image -->
+<!ATTLIST IMG
+  %attrs;                              -- %coreattrs, %i18n, %events --
+  src         %URI;          #REQUIRED -- URI of image to embed --
+  height      %Length;       #IMPLIED  -- override height --
+  width       %Length;       #IMPLIED  -- override width --
+  >
+
+<!ELEMENT HEAD O O (DEFVAR)*           -- document head -->
+<!ATTLIST HEAD
+  %i18n;                               -- lang, dir --
+  >
+
+<!ELEMENT DEFVAR - O EMPTY             -- variable definition -->
+<!ATTLIST DEFVAR
+  name        CDATA          #REQUIRED -- name
+  value       CDATA          #REQUIRED -- value
+  >
+
+
+<!ENTITY % html.content "HEAD, PAGE">
+
+<!ELEMENT CUPSFORM - - (HEAD) (PAGE)+  -- document root element -->
+<!ATTLIST CUPSFORM
+  %i18n;                               -- lang, dir --
+  >
+
+ +

CUPS PostScript File

+ +

CUPS PostScript files are device-dependent Adobe PostScript program files. +The PostScript language is described in the + +Adobe PostScript Language Reference Manual, Third Edition. + +

The MIME type for CUPS PostScript files is +application/vnd.cups-postscript. + +

CUPS Raster File

+ +

CUPS raster files are device-dependent raster image files that contain a +PostScript page device dictionary and device-dependent raster imagery for +each page in the document. These files are used to transfer raster data +from the PostScript and image file RIPs to device-dependent filters that +convert the raster data to a printable format. + +

A raster file begins with a four byte synchronization word: 0x52615374 +("RaSt") for big-endian architectures and 0x74536152 ("tSaR") for little-endian +architectures. The writer of the raster file will use the native word order, +and the reader is responsible for detecting a reversed word order file and +swapping bytes as needed. The CUPS Image Library raster functions perform +this function automatically. + +

Following the synchronization word are a series of raster pages. Each page +starts with a page device dictionary header and is followed immediately by the +raster data for that page. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BytesDescriptionValues
0-63MediaClassNul-terminated ASCII string
64-127MediaColorNul-terminated ASCII string
128-191MediaTypeNul-terminated ASCII string
192-255OutputTypeNul-terminated ASCII string
256-259AdvanceDistance0 to 232 - 1 points
260-263AdvanceMedia0 = Never advance roll
+ 1 = Advance roll after file
+ 2 = Advance roll after job
+ 3 = Advance roll after set
+ 4 = Advance roll after page
264-267Collate0 = do not collate copies
+ 1 = collate copies
268-271CutMedia0 = Never cut media
+ 1 = Cut roll after file
+ 2 = Cut roll after job
+ 3 = Cut roll after set
+ 4 = Cut roll after page
272-275Duplex0 = Print single-sided
+ 1 = Print double-sided
276-283HWResolutionHorizontal and vertical resolution in dots-per-inch.
284-299ImagingBoundingBoxFour integers giving the left, bottom, right, and top positions + of the page bounding box in points
300-303InsertSheet0 = Do not insert separator sheets
+ 1 = Insert separator sheets
304-307Jog0 = Do no jog pages
+ 1 = Jog pages after file
+ 2 = Jog pages after job
+ 3 = Jog pages after set
308-311LeadingEdge0 = Top edge is first
+ 1 = Right edge is first
+ 2 = Bottom edge is first
+ 3 = Left edge is first
312-319MarginsLeft and bottom origin of image in points
320-323ManualFeed0 = Do not manually feed media
+ 1 = Manually feed media
324-327MediaPositionInput slot position from 0 to N
328-331MediaWeightMedia weight in grams per meter squared
332-335MirrorPrint0 = Do not mirror prints
+ 1 = Mirror prints
336-339NegativePrint0 = Do not invert prints
+ 1 = Invert prints
340-343NumCopies1 to 232 - 1
344-347Orientation0 = Do not rotate page
+ 1 = Rotate page counter-clockwise
+ 2 = Turn page upside down
+ 3 = Rotate page clockwise
348-351OutputFaceUp0 = Output face down
+ 1 = Output face up
352-359PageSizeWidth and length in points
360-363Separations0 = Print composite image
+ 1 = Print color separations
364-367TraySwitch0 = Do not change trays if selected tray is empty
+ 1 = Change trays if selected tray is empty
368-371Tumble0 = Do not rotate even pages when duplexing
+ 1 = Rotate even pages when duplexing
372-375cupsWidthWidth of page image in pixels
376-379cupsHeightHeight of page image in pixels
380-383cupsMediaTypeDriver-specific 0 to 232 - 1
384-387cupsBitsPerColor1, 2, 4, 8 bits
388-391cupsBitsPerPixel1 to 32 bits
392-395cupsBytesPerLine1 to 232 - 1 bytes
396-399cupsColorOrder0 = chunky pixels (CMYK CMYK CMYK)
+ 1 = banded pixels (CCC MMM YYY KKK)
+ 2 = planar pixels (CCC... MMM... YYY... KKK...)
400-403cupsColorSpace0 = white
+ 1 = RGB
+ 2 = RGBA
+ 3 = black
+ 4 = CMY
+ 5 = YMC
+ 6 = CMYK
+ 7 = YMCK
+ 8 = KCMY
+ 9 = KCMYcm
404-407cupsCompressionDriver-specific 0 to 232 - 1
408-411cupsRowCountDriver-specific 0 to 232 - 1
412-415cupsRowFeedDriver-specific 0 to 232 - 1
416-419cupsRowStepDriver-specific 0 to 232 - 1
+ +

The MIME type for CUPS Raster files is +application/vnd.cups-raster. + +

CUPS Raw Files

+ +

Raw files are printer-dependent print files that are in a format suitable +to the destination printer (e.g. HP-PCL, HP-RTL, etc.) The MIME type for CUPS +Raw files is application/vnd.cups-raw. + +

Internet Printing Protocol

+ +

The Internet Printing Protocol and the CUPS extensions to it are +described in the CUPS Implementation of IPP document. + +

Line Printer Daemon Protocol

+ +

The Line Printer Daemon (LPD) protocol is described by +RFC 1179: Line Printer Daemon +Protocol. + +

The URI method name for LPD is "lpd". + +

Server Message Block Protocol

+ +

The Server Message Block (SMB) and related Common Internet File +System (CIFS) protocols are described at +http://anu.samba.org/cifs. + +

The URI method name for SMB is "smb". Support for this protocol is +provided via the SAMBA smbspool(1) program provided with +SAMBA 2.0.6 and higher. + +

Directories

+ +
+ +
/etc/cups +
The scheduler configuration and MIME files reside here. + +
/etc/cups/certs +
The authentication certificates reside here. + +
/etc/cups/interfaces +
System V interface scripts reside here. + +
/etc/cups/ppd +
This directory contains PPD files for each printer. + +
/usr/bin +
The cancel, lp, lpq, + lpr, lprm, and lpstat commands + reside here. + +
/usr/lib, /usr/lib32 +
The shared libraries (DSOs) reside here. + +
/usr/lib/cups/backend +
The backend filters reside here. + +
/usr/lib/cups/cgi-bin +
The CGI programs reside here. + +
/usr/lib/cups/daemon +
The polling and LPD daemons reside here. + +
/usr/lib/cups/filter +
The file filters reside here. + +
/usr/sbin +
The accept, cupsd, + lpadmin, lpc, and reject + commands reside here. + +
/usr/share/cups +
This is the root directory of the CUPS static data. + +
/usr/share/cups/charsets +
The character set files reside here. + +
/usr/share/cups/data +
The filter data files reside here. + +
/usr/share/cups/fonts +
The pstoraster font files reside here. + +
/usr/share/cups/model +
The sample PPD files reside here. + +
/usr/share/cups/pstoraster +
The pstoraster data files reside here. + +
/usr/share/doc/cups +
The scheduler documentation files reside here. + +
/var/log/cups +
The access_log, error_log, and + page_log files reside here. + +
/var/spool/cups +
This directory contains print job files. + +
+ + + + + diff --git a/doc/images/accept-jobs.gif b/doc/images/accept-jobs.gif new file mode 100644 index 0000000000000000000000000000000000000000..9da7a0dce11b175dafc1f23c698367a584570a0a GIT binary patch literal 259 zc-jF20sQ_)Nk%v~VOana0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui09gPO z000Bf2)ZFdCCW*wy*O)0h6qc@3|ncQs5O8hV5D#?TZZ_~c#hUep#Q)OixH-;FljX}YJw1!H5r;IgHn-{ceE1IM+xKXBDiBI` zcVb9?iiL-PdK(0UYGZX*NR)z(YMGpLeI1O8h?b;&rJAUv6&|6FuBLpBR+Y4}f)yXF zjeDMCyk2Xwyk~X8!xbPzN1MwiPf*Rw(IqS{)2i1OJPSA3-Wl5=0m|Ry1uHG$4wB|a J9UmglrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui089WB z000BO2)ZFdCCW*wy*L*#L|7m*Xk=-c!xsX^>ArAegl%l!*sKJ2?@Ovt=71qmjFp2D ziS!KsykVg^p-wGLqZQZC5UI**By8P^r(sEYY>qgjV>LUDPF}QfG5%b6z|Tx{e1b=I zgKZK75JgLYbdFVbYD<$glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui08#)H z000BY2)ZFdCCW*wy*OJkL|7m*Xk=-g)bNFXfxd7&8KEoRI7ur(?*En5D09FRDaXlS zxwIrJPt*X=BNn0(tX7G_o*J5Bw3#GBx!3ejyl!6IYK+4gDc9Hcb2guT*Z+Nea25}A zfp&*bOo)PejeuSg1Q14xj*o$tXqb3!On?|1Mo6HYnV_4dom&|lqiAiAtfY{Rs;Cwo zua{#H!Cg9(kD9$Hq+P^)gS@K+1M&9+zyoAKO7z`2>?5A CbZnvk literal 0 Hc-jL100001 diff --git a/doc/images/cancel-job.gif b/doc/images/cancel-job.gif new file mode 100644 index 0000000000000000000000000000000000000000..3cc1e23bc650c00b22adb435e40862516f3b9d66 GIT binary patch literal 248 zc-jH@00;j^Nk%v~VN(DU0KxzO%*>g9fM7yGF&G#U0|Np800384LI3~%EC2ui08;=I z000BU2)ZFdCCW*wy*OVoL|7m*Xk=-g)$oOYfxd7|8KEoRcu6Zk?*Eq62y-YNfRrO~ zsTlxz%!m?Mm|CpKQX^V1N{+>e_ZyaGrsHZAOL1_;U#W5)SDWn@`n}ASJlz+o`iLgkro}5p{IMOgI%g~i4`6iMpj;6b!)U` yp15MVV3-jfLsY~vPEW?5W@?y9E literal 0 Hc-jL100001 diff --git a/doc/images/cancel-jobs.gif b/doc/images/cancel-jobs.gif new file mode 100644 index 0000000000000000000000000000000000000000..2384b903c673223b776c21f76c2ea6a9ad5f9d14 GIT binary patch literal 255 zc-jH~0093-Nk%v~VOana0KxzO%*>g9fM7yGF&G#U0|Np800384LI3~%EC2ui09gPO z000Bb2)ZFdCCW*wy*O)0h6qc@3|ncQs5O8hV5D#?TZZ_~c#hUep#Q)Oi-b8C55Wnt z$V?3YzGh^Zq*|;Ltf?Wb93@DjQVb>+w8}CyY&BaP-Sl+2tb^xx^!>ai+xZs{aaVYN zT5E-bfQEe=1P~W`XJ3ndW0aDNd3%!?9fO6ImYk%arj=P39vN+?h^VlKjd_2g6dxK# zZDL`Zlyt9IZoh0}LI6Zb%0N$0%g;J2F3{94JPS9~+8Ng&0m<9p1uHGy4v^x?9Umh0fMCo*G0Yee%mV_<007KaLI3~%EC2ui06G8^ z000A@2)ZFdCCW*wy^#zNmS+Pdj^s3SA7GShdl}#A&NQq9bUvdYcKiq3C}TH MbhQ>594QF^J97d~lmGw# literal 0 Hc-jL100001 diff --git a/doc/images/classes.gif b/doc/images/classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..ace15df98035c8ff3e41036b0be59f2664f7d0d3 GIT binary patch literal 591 zc-jF^08~U*5-X9+fD*emQ%-t<0(_wQriGZ zZZazx6{;H!rfZ&NF^DjR%UP$gL12(v1z%TG%JvI>t<>1d$R6}E?QFaBuG=p#CYq`w ziZLKnI#?fMDjR}LReukMU5I;WPjg%#kve@k4n}f;gCRUfWn^cOf{Z>uD@%zdL!5^? zZErJON@0|Ace@NlyuZK^mQ+k1!FGr)XqH-AsBeLx4HT-7rY(4&t$Tq1JGN%5Vb2<> zecNi2Y_Y^HEYhh!)TfI?l!TXqlgPG)&Q*(hvyg$SQ4d$HfyWfAV+V3h%sVe{>bzsg*v?&fS|wvO z;ipJR`P$Vo+Q`t9b~&`r2nMgIIb~O{sU$>Hj3ZL$G-e2z&tV~XEGM?mG=|~0JOR9Q zx~ivQkCoAuorL9KVzjCZsL7LY2n_~8V(13pGyvmhOX_!0g^}SfQhCYc7E-lJ z<8mqB@6klgfj#Q`%u%b%(iC7vD_0O};S&#LvOb}>9YnB~>XIW%d3BaYhzM(>GRB~0 zFrl4c{!(`{Okt{tJ(sb!5}DI%@Dx;B@|5J*;qU$?8QeVQ>viyE2Cb&1&70FFgU_{d d<`(xg{4v$bVfLjbUglrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0C4~m z000B^2)ZFdCCW*wy*TU5BN;-ljLguTXsWK!Ad-N=&UC#Rq-^heKjDgiZ%CxQOqhf6 zpjsA}N(=KcRSf{bB1XL0ms$%xn6?5ILsAra&K{R zg=>6igoRs;gNKWYhL0EzfOUzJlaZN%f|`6#nVX%Ak{1LJRI7)jq^+=nPMCqNuTZBJ zAD51=x2C|FW23#2oV1k!8Fs?K$B2}lVPl@I)fpjTvx?HOZlS)iQsdr=+{6|lNJXsd u?pIju#q#biG4$v7L_iBV`u{%ojR>#~purU`U<`Di>YzhZAnYwj002AUeve21 literal 0 Hc-jL100001 diff --git a/doc/images/continue.gif b/doc/images/continue.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff774adb348deca51456cc9934e33be9f9aea9a9 GIT binary patch literal 224 zc-jHr03ZKHNk%v~VMG8F0KxzO%*>g9reH#cF&J_Z17`vNW&l@_LI3~%EC2ui07L*3 z000B62)ZFdCCW*wy;zbV!urgRjbxb(9tap_>$V2SzI1KHN?`ANk&2ju@bDrQjJ?SK zpbJirC1{e;a9)NIqA-FrYLVdV7UQs1!bdN6oo1uamWP@0&brx0yc%C2K(2syf_r&| zg+pT&8*@)~hI@pOd>9-VP?C>>j$W7+9V3WOiEmnZVvmUy9zavABTG!KvKT2Vv$qmB a3p2Q`x*q|oy*nr>zz%=IB^w?4ZZ&};` literal 0 Hc-jL100001 diff --git a/doc/images/cups-bar.gif b/doc/images/cups-bar.gif new file mode 100644 index 0000000000000000000000000000000000000000..b2bdf4b520db437c310a503ba6b27bd696fe580c GIT binary patch literal 1242 zc-jHl1SR`NNk%w1VMhQ`0P_F) z%*@RH0002Y%*@Qp%*@QpA^8LW000dDEC2ui07n2)07C@+u*pfQy*TU5@nB#mj$~-m;k{Y;ytnIwsiZN&m4v7XswuJ8gOvP;Gl130ww6EH@o#Dg|j9ca1AmkDFj8 zS{XKXAY>9XR*yh;F?nB{3I?LFK|*ykoVOOI8aS=Ez7hkevLz`Ky1x^{C@{=11JBPe z!#)kYEq7h8bV`VXN;m-rY8O>d zV4O-5gpmkfKwlewP0FNM(xAYTdTbgbP$5T20E_-I9Aa?dDMbQn$TDCdW`L3hRp?Su zSefM$3x&#Zmgo{wrj<0&!r?>#rCE;wE@l2gpdhHUX3w^j(xkKlO`R|&P)&)oD+y}t zHUJpLEGj^I5&{Ap`l2TWbE5UJJ5R+JO2wxz2F8>U3ulsNgIVvisq2rrP#;&yS( zbrdkBC76bwM#^&|K|2~%USCfQ3$59c$cZ-)bpQkAh5&@OU=j=j(3+4300C&f#o5S! z@{__U4n#D3nji=rWRA~B#>1_=DqA;MG35)U$TJ{9?g&X>Wysze;W7wKq{oiLFH4F% zg^{lW%l|6;3%EuStFR5&j#?Ks`YsM9$o`O9Df;12N>z%f!#DYgV7OBY^vsFGJ*#emy$DgA^Ui$uZT;BpW~qJjVg@QBm^ zJ{Eu!M@dkCSB@N*GUAddBDq0R1)A_oT}L9R7ma{aV@r-EVrgNHQF{56dz-Xa)Kgdq zsO2LFgt<&v+^GQdFoY=os0k$>s%z?nfpc*hu38 z12|;4#{!gEB*<*>7-K|pWWqAb2g%4&USOq-vW5nS!cahw@<~XCYH{o#4RD`^QyB&b z2*+3^>6Ao`iCQ#4SQ*EAQtp~OoLKq1siTrXA{MkkiG z;fSqcU|Itaq11MWr@$zv2M%Qnm(h4)lsZr%r}C>$0r2J*gbJr5;+vdL^wZm|g{^8D zH?sY<(FYqk zgh>kCxWq2|DxU44`wI^Fm&<5&ru~QwqLPKla&$zaOj)E`ph=@*rp#yWzUW;2h77%` zlobTInG;k~d`?-HIvMrMTmybS0Z^L-!%#B@0MLk8`eg3@ZUk*aN8cJ5-u?#YiwFP! EJKUogO#lD@ literal 0 Hc-jL100001 diff --git a/doc/images/cups-block-diagram.gif b/doc/images/cups-block-diagram.gif new file mode 100644 index 0000000000000000000000000000000000000000..2fe505e44b91deeb805b568a4db3a0fb508b0805 GIT binary patch literal 11637 zc-jGVEsD}dNk%w1VXXsI0pkDw2nGl@j*28mNsdrbK4^1IG&XX^bWBTSySu%Iii>h` zzFwzbprxnV;NQk_bpQYVA^8LW3IGoPEC2ui0IdU60YC))@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_hclL&yI5Fii`0?4Ft$!t2G(5MtiC=P{!M1#lW9RLJ_cuX#v z&*-#z&2GEj@VIXf`cFpKtTdiii?bmj*pCoL|cTF8ed_1nwy+) z0YL-{V+2A0a6z48sHXs_uCK6keU`Mfwznmu0Fb=BzQ4dxpp`>@gP5_&%9;VXU}CFk z(W~BLiV^yfNT<=GNRujE%Cu>eZ6IULX!%mARUI>(YTeod=pdn2 z!-^F_b*$O55X+)n%OWe+w_Cjm0?W4UShaTZ>Rrfguip=Dk7~S96yK0Uy5Ld?;t@d9 zzmRX?jZC?6iOH5J2gVqL5hx~yl5}1&8cAu>yFP6so!Y1_1h8Yvo=v;9?c2C14Fym@ zf$!hIg9{%{ytwh>$dfBy&b+zv=g^}|pH98H_2?fn1MaK6@@Cf>i#!R>)+46|MTqdZT^5+fO>t$lud^ExRD(WqoR+`U<16Y`9t1preAnUGS zrAQaAz`7G_uxI&N>#a@=<`}We{)%PnHLW%)?F^&xXl)R>O$#AxEoOP`x8PnwqHnNi zYp!L_A{gzt?4nR@xI$#x?!5HYOKG~-u50hU8@&6iy!-|%@W89W3oXG2W8kk%04MD5 z!w|1DY{U*P952NfXRI+T6K_1QzYTjV^2j8+&~bMh7U00jEVu0P%P_|*^UO5YZ1c@H z=dAP2JojAln4AV}-J~TKP4UUvrR?+4OgHWH(@;nKG|)mcA8|WO=iAjhVvzb zlLj%s-;hTx`Q(&WZh6!G4Z#{`qh4Pwbr3d#&a&tZkiN2)k2^5Hm@Pxu@;0fje4^)4 z2RVYbMl;mdh@&D(<0?Ktf|o4)euUOsJn&&!vMI?KrGO}ymIPp`a7nhQ~toSj?G zboDNqPWtep^Okz_tpo7#n6W!ByZ1}mZuR`hH4Z@g@Yme@0LhFzf(@WHHl<5M32Cul$l0+@B(J+WbMBA1CV8b8!CPQ8%A{lkJ#s3J8fmw{B9Op>K;-wHK zE2K;d>&Qnr%8-75B%B1iq`^WO@{ov3q#_r|$VNKyk&uj}BqvG9N?P)gn9QUmH_1s% zN)eA#d{c@#Ny<{1@|37dr6WnG%2vAam4zgl-DYX8Jkk$oVXIk@`*o@&DlbFqJdh?r5i)LD;S)*!#^PK2R zC(X7oNH{`qgoI3D|H_v-*uBn*#(SRXSXVyj!4r=BY+ydE7&8Zku!P4GLi+qUgnCAh zp+a!z2mTj0zd;wh`J|no%jDECz3QTF=*!h5EhSYo*G-^X##=d(FaGCmqX$3n-RTR$Cst8Re zRLKX=s$TG`%NuA+kH^uknl-9EZE8ntszh-fQv)a!D%hH*R*FKetS*&l>MlCbsOB`R zA4DtZ>iSW(%GG)8gKr$oVE-)qp92+n}7dCRLT@f!HR2zHxwJAmCIZ1=%VI7G;J@GC$x zcfivHLIKe5i4E762xSP8e(^gB5Qq2~ANKGVRD<92is29=CWQdZ00i<*1H$zTq% zn8W;J97Xw-Q@%)RX`A5i7NNCF+42sI+~bJwxXz(EGcD6>W#7tK2Xw}BCG;%*Xvh%S zZhY=DZ~vTwKo?pNhkkT{?!4ec10zUKsKRl{!x|tB!NICYP?7dD4Mw**glFJ{FQ>Nhy6Z z{No@GdApaDXLv(a;?RZ^zP00Vk-PlmFxQX6w`KCTqCDk_S$SrBm+JnW`~2rX54zBY zPV}M=T~{SH>8mGzYn%i35Z+z7tBkd3sRsz+yToqOoz4`EB*5yx0&ms9ZW*jUngI%k z+hKgN-HaGls2 zna}<1`|Yvt@V!)ke?@~9G_VupzVqpGd$Udd+x4ry^>4RL@BZ8W{$B(CJH#Io@=Z&h#_6nZC?Z&YR4OBv~JWFaNcHzcldmXm4<+GReYFEWS9>82NVAHhv2k^nDTGA zlYP&jh>0VA(h-D)IEj>4J~z03W*8ZTSc%w#h(FkH{&aJEqPQJOH;Q60h^Cl|5toUo zIB2Zcim-T0s2GcF@ru8c0H2tPy10wQ@pah~hyl_7yqJqOG>o6Phn$#r{Wt6i{FYhIgfc1*lU9a)kT%k1+#=-WW627?2tihFaK;Vug_ZXgX@QK?B%@4Ea$Q z6o=XPLd*zR(0G5qWP@+@>n1ysTQ3vQc@+dp>m`(h1kt-RK`eTlQwvjS< zlix&*Gl-KssZJUBRyNs_LfK5zSc67+lt`KWluEgjOqpPpxL}solu|jBR9Tf)d6nT% z3k?7pXon?50Ffl6K}A3%w}k+%Co)lqm1?<`Y}uA>DN?>ji;aR>akzG%Rw{1Cf&>tE z34>%~_LqPem?%+Za=8~ja1Ct7b&8N$hY^?T;+KLMnUXn~%RrcgIe46=n1XQ_X9*}M zMwtcSX;=^na&TjtV47=ynxL6sBzKu((O+4nnOh+V3&1OoxthwLn!3OWub`S~;G4Ml zT$bsY@SqE^DVvaT2uK$cZ24uuNe-xH1Y{s%Wk8+Q@MY0J3eH($FJ@vTmS3g`4kfmo zp9u=j84v~bmQ4ASb+&cLi7bcE7?}Q71GjmesZa#cPz}JjUn91k27sDCKw{p&4dTfL z{%N0`Fq~KCj8f*F?`bPSAfH}_pyUv0^EI6pI$|1%YM*HU{e=zRc^CyM1|0fd`9-10 zprG(Ei$`+>cln?>cLfr93>}K1HhQCzsiNJ%qQq4i6!D@kiWEP}T{G$rHHxE1nxtT+ zquRlvTVrbB0i;373yeu5U7>q_P|FcMc_;xVN_Vx|s)rCp$< zIl!e~8mDq<5Mf$&42otHN2P3rAa4d|Lb_(@Nf?P)4>~skZi)kGsh*0usEpdEM>(H% zijIz4o$3LoiZG!ns%l26bC#*8 z3MY~}s~p3rv(&1tiVuY<1BXhBt7@wm5Uc~EtGj9sy&40*8jHj#tQOF$0b{I+pqx!W zt@n_pT9K?Uu&l5Mt?+&}$WErIH||ZONAw=BV^qul9Pc zJ_o7ZfvbpCuD;-)N}y@Gh90fa9;cBWslg!r+6&qW87*gw5F4?`W~vKXtA!@5iZGgc zA_RBIvD|ee1`D$GW^t?WuE7SY5c04RyRs}RG!(m{{8~2{`(Rb@qPk|Op%^ME+p^D5 zmvVD`(Kkj2_ZvP7{(a>pM1-?Dc*wIe)S8Xrt@|>w$4YBC+i^X_w9@ggjyQioyR>=8 zHrO|Agi|6iq$YESwL{~yixRV1Bejr_r)N59eb%slv9o9kgpf!$0;fiAhkX{A9E@lt z-o}Dod$(7kubRQOt9Wruk*5|HuzK>bF6t*JOCWY@xZu`rV=Hc%3x9YkwqP55z@u(& zLvTKbxxAAqP+Ln2J8_JAC+*53NMKx28fTR|Y*&lAjTkqJgM9)tZa!#{pvy+ak$t9{ zx4K&#FT10PYcy{A2##B@t#PwS@M{YDy6{@HjdHok+r8fFMu;03tJ_PhJGHN>y>i06 z-@Cr-tGsIdyJHqBXwPfDk3hG6p}y^#zxlhoP1?LgGr#oP2===d_^ZDL?7jRerv6(p z035)JFu>pHtLPiSkhZ`jvkk}Tz(^6F6kH2K(7~24zWXvJwX4Av;SB5v!lfFaDqO+w z`)Unow>t+h9E{f16}F6NIM)UEOiVJ zhjAOEd&(O(oW$vHEm#}_JO?iauzLuQ00dC9SYQNx8f<`iEd@XT3Gl>QtPtSx#xKyt z-}1$B`~VG5#CO~s@Uq7&K*zY_$AbJSA~nb<0LbBB$A-MfZ$eUxYyyZp1d9B~lnfu? zRmuJ%5XoeO$()=S2G+?SfXI^!%A~BoFI>tVK*ytu%B=hsJ)EjMx5}+N%X#t2uq?^6 zoXdV;%eTDAy8O#_!OL8r$@p5##(d273e53l!Lz51Ls>_jc))_B%r?i&zvs-)JV((i z&E7`M)qKhX5|r5tL)*;FK;+G`XwBn?&EuR!{;#I9XD< zkXVPpA-G@y99c5FdMMArM9({5&-V;J`P_p>8-IHXw2wGOgu)n`hs+wi(Hy;&Zfs}Z z93Tu0KWglOE%-qPX@3vRh7di`UfUf1*2KYsj167W&lIj9tj_(%&gB=65@|pWdHzpO zfTI`fVK1vw81*WM)8LP(Peq0lpJ<@nLJ%GD^t)BiWwXC*=^dDQykkED%M37FVj zawt@tdoAhK2$WQ8wS*uAIu|J0>$6h{HQUmYQy%%#QFzv4MNbK7Q(M(KY;{pBg^wT@ zP|K6j4ye(Zoi{Lv)lQ_;h07{v6D8g;<+u?MT6*Uj zoZji4{^_6|>Y_gCq+aT#e(I>6>Z-o#tlsLb{_3#)>Q=$yIM4vGe(SiN>$<+{p3b|x zej>ac?7}|mp^nfAJ?L^w>&EWQ%Fe9FzURg!IPa^gTTy#J=lsBl4Ok>G%ge#*>mmFH=`#IwVf?L~ZmPn2*Ub z^&%qWf9Ud9WZ(!$+$?Fy~{el&iB2IY}ixIiYvQ*Q4< zWPbI*P5^q$;4+EwG{fA1zgPFe@noIbb}x~b#rQ)B_e)gS4yiX^Z`h)9QE;936WQ^K zZ!<=HP%Ihsx*g*%E`|}b_yYb_1^HDmpW;2O^}J;Al;!p4$NO}DS5Jk0C*ArADM7zK zRly&EEYF9e|3qL}+8CIPRA1r*_5A?J_g2L-VE(UIy!+lSKKO+FPXnY@u20$})cIn6 z_n%GtyJY;6_2IU!l6BSd5HQ?y0MJ>iq}qalqbzJ9F%KNHGF3}BmS?)QZ#>s!?RmCc zP&nj$3Pfa5xnwq-Pbk!a@Kvo>Y*xGFcD-M4SUe_!6`*KZy=J%FZ+Lvy`vF99d|toj z_x-o2GQmN@Lc>EutFxoOM#o3UNXZyFpvg|fB^*#w5Q@Z<0rLtRNI+%b$uRK<7+~4b)#_EOAj=gXz<_B|l|{vlC0o|)S+r@@uJw8J>sz>S zMKw?WQ6g5ndG+q4Dsfx^1;^xC3(MB6iZG3wz1IT-kK$m>yyR_6PCM1ivrD0= zG$1u0Wz!pRcx1^xm{R`y@lhW`ipernO@ygYLw`K9C0S`q@>NsMlXO&Kixp=}On=+c zQ)ZjR3d(B2K}wqag6$6kU27UL+aBfN)}>y*T+wdb6<)s^2akq37K6=xJ4_0xvoCn^K(U*$k%3yKF zCcDtChif|7r~U!pIO@Uj2Dxg$=i3cy0JMIF>$($Hd~xIo=i7?B_kJ8MjqQ^+aLhS# z&;r5@cLs6BLl=GYp6j*cN)-jcmDard1uh~-~0A=BeaVzK6{OlKhxyeOND-X@|Tu=LF%iIEBL-r z)jniN|L&f1<-up(_VV-B|J?HxOke%CuHVG_;R9+WCb9fMe z^!r}c{%U6|AO=y0LnLAmjd;XyRLF%Fgkb=$7a<(pLn2fBNENMk#VK+SA2x&{4;yH| zCWbK!FBD@LwZTL)qC|%CqDU6eltqeEjfA2CV;aRsMmy%w8Fw8!Hd#tkis6*0 z)P*NO3CTg?i+_@+6fR!n#9vYhb*gEpuB z6F&py#xt0q8P(RAjCRr!GV>H@8VOoZWTI0-`>ajts1qpR$;JmX9l%`arD`ja*UFuScb~J_=l_@!CTGMj^KujUc%6Bkgj;UP6 zB2OIF2gJl8B$}gw%s4|*o%&R$Mpdd)1;}-lxG|g_;-j1?Y5R1Vk&(7(Q^-T7La!H+ zzj@}UR1HS~su7Qo96+vfrE6X7dRM&WRj+&HYhV5PSHK2Vu!ALRVGVmoj;g!SQ7 zp_WxaY;`kT?FeO`Skkh7^&;2nDrM^<%E!SqOQR)iX-#`t)TUOot7UC#UHksp);4x> z9L1?*VW(N_aTd2f)huRlYu2xJcDMAQD1$@`TjVBJxyxm4bDjHK=yFK5kE3l(ZL68s zX+*6S*)DG%u!3$<^gB{%9>GG|*GQDm(tCHX795_D-esG7e1dfr+7erah z&^e;Cp@)d$#8)zzhfKU75_?$2Q;M)D?R#G@RM^7%ya4$bDl1GJAv^ z<{4jE%O`#^jKAE}55>67NZxaYGyoVm+d0o)?lYV{T;q;SxT9!JGaEt6w>KO5!GWey zq4Dfx4<*^lcOI>#70_itcgWM1mNbzOZ9%M>xeScP%{=&d+2MY&&FhJDsTpkPCUZK} z7@7x)$#LXL1E9)H)pf5iZR;VQ+G%B0^%yZ6re_0qo3qAFt&uHXT#IiTvj5J;%zETn=qd z>FK{7_{uk3@P#iO!VkCc&Uv0=iqps90v7N&kT)!eath?jQM%UM{&u)SH|M>JIL}!P zQlCp(tOBmL?BwO~POV)zZI6554S#sl&V71ym-yXnGxnikyk)ZMu4m$dR!2{=dW1)O z=RN=VTrV}xysJOV zfj!tDHnxgD37kL*tiXW~J)J|q1Z1}bWI(`izztN8_W%I=2*Eodzh(<74}2X^F+npj zG8a6--dnEp#X_3_}~a7c}IXD-4G* zj6=HPLNtWHFKk1;*bODJLjXFsGX%stR73titc*3|!@Q7`1As$9e4IHHhdO*j(Qpob zuqr}ifT^PmMLfH4IDko{#OgUXbPz@5_y<$8f(FpUh|r-%i=vWa07p#4--*O=2t`_q z3rpMwOw2_rV1T+f2QJDSSX40uz(rq#AyPDgWSoqCXhu~6MsKr+ESiWby2g*FMtle{ z29O+RG$UIi2W0$4l-Nal=tXiYga+6KVEiW8|*kZwePSxm=DTE@1r$GF%BeeB0( z499X9M}K?=bF2q+97u!&M0`}Sgj9-rXh?{(Lx3~~fs9CMC`frYNQ>M^7hK4{;K+oy z2ap^|7o5m*s7R7*28=8RjZ8_GH2yP>{I!?FhI*Jun^ZNEln0c&NnKb;acD`N3`&8D z$*mB|FFFUKOiF~x$$8jGr4$99v;d%dN~(0HCalUqKuWCKN`bmct{elOoXW2pOI-3w zvIK*2I7_uuCbL{iF2G2!bW6EZq_&*PEEos7%*%~JLA@LVbBxQr49q5~OTnyz`zuVu zWJ117%rLM-z+_Cw96vlv7P@dhxU0F+dWvzVoOik5X zP1bBp*L+Rbj7`~`P1>x@*0ey}BnZ#cLeNwSUI+%@Oof-@%;h@F-7LM{Op4zOPUh5v z;Uv!FGS1_)yTw$F>imuC%ue!bgze-`*YeKqRJG(piSaB? z_}qi@L{HXI&-KKy_B@IAj8FcIgZZRS)w0j~gsl8ri2dwO1Z9K&1kl7wzX9FA0#%3u zO;8Gjf(2zz(-P1JwXX1dKs2aO5M6@{eJxTHH%oIedEgLIw7TeY&<#b-4tBaoyad2dIE~ZQdQ1yBQqk~IRS*dW z7=RBofeQfBAQ0332E`I7-88DpG&7Vt%`*bqY*a^mR7j0fNu5+mtyD|BR7|Z+LqrHJ zMF>1ig%b$VI|$WK1ymXk)YJMl6dTPmEjTg_kylOCMRf&JtyNpigiSq&PCbZEMTJt$ z0aE?bTcw0pH7!ufwI~&~OheHsQPo!M&RM;KVVzcL)q`Aphh2S#UOk0hm4Q+v0T7!2 zJ|%}y4S^4kfN>oMY3&76ZBP&xwx=^WBY@Wyd)E1SS2b1EA&u5*?N@(=gKKq%Y;}ii z)CY$)tO}ir`3V3eS#9D(XaJ|p*^FN<&vYtRjBpW zm?R0 zFEdenEz=ScH&XkvB4gHnTd`3?WDPOm`TAT~2;KJWUKoz!@-5sm&fy!N-LW;@8IasD zj$OG`TBudyOMc-DhTIn(}Wg6CI zZ*JoSmS7ErV1X@K$-w1YX4hl3U|&|a7*n~HBQ#^~QGSlPJ*(%dP38vvweDqJb7o_8 zCR}a4VT2}ScCLXsc3)!k-Gqi?RsP^Lwpm8-01mij7}(w3ZGqywV|PaWSz2BXd7fuk z*kxa?vnMNNE{n0w{ZX0TwVD>_NG52Oh5{Gv>FiADX|QE$SZSbM1((J;nC7&6{u0DmNUND{J<<+`sOCD>sR#LBy2BNM8 zv2N>3DC_7t)+96JE5U0ajjbxCYrtO8w}yteriQr=Z0$VjeG`X|{V>KxF11E%$qv!M zeul!HhQpq0N3d%+jcm>SZ2qk5JpyaU$ZXK=1J1@!&pvI|Zcfo|hRc=)({AlNNbL*$ zYue6jvc=<>I$H*rZQX_g+Xm39c3|T^ZsbnxBRXlK_3Z_LK;{09Zt0$G>c$5xO~BYz z%Iv;w?k0roHp=hrZt+$n(vHmV9&hySg7fCd^-gd1=D^op&-Q+A`kwEZv~T)OZ~S)2 z{myUk?r)L=aR0t;0SCzfAMh7F@QqY(1RqcakH`ma@b8T9hNN%_-%Sfg$PDM3C#-G{ z|8NkWZss=I_!bSQ4sjGuaTSj$Ne*roe}xiPh7CUi;C^u%PlHxi>l@#3NQm)dm~lg> zaULJ?B*<|hKXOU%aby7ULJ)E!e{vi!awwm2K2UOEU~)omaw^|)l5TM>|8h34@>VKu zxzKVj-*PEmg^4a>U;yPJSYeVbY08H41|D(6CG)s2^Zp7w2OTGZ!%c%f=jt>^1vlSj ztVV)B7u>)t^f%|>^+jI}PMZKc5SLC|vw?bb(^0y+=#PH*c$pY$vKbYLZQH3(st zh4iPjWK{1@NjF$ZPYO#H1WY&F6@K*^z;(ZE?NEnxI%o6}_TO@lfN-5$a>d`j_zN3A zby*JSL!W`m#b!TsY88W7YPVxLrd(@RR}6@D12%MV=<_58aXV*^T95R=O<`}R-gSTB z^X>LwNA_^f_Hv+iZXfGj=LB!(;Wmc%aBcw)hIdFmVF~7D8?a#j?({%!_S8jngZI<; zE!=N~^Z@qvxJ6(7l~`3rS`e?Eb9ePDHePWC{$Py%P!f1|fp>NfhFcp>;eJu(NXr#wsofr2>5c7EY z_|X1al&9m;Ys~l zp#RgN|M!G``ZP}9hUR&Y?)o{7U8%i$wJmouv-_HFiegzx&Xk6D)w_MfNw7&zZQ_vngNT~kKbxzFg4mwkwK`m$I0$k+8fpn7*= zeE8(sQm*}*e_I@8{oyBmvH#Q1H+C)l=6Rsz{7YE(Rxf9WCWmbo_FuDo%Fp{}=l*-Q zcg)rPR37|RzV_1x_wYA%>u={H^!@Ub2e^d_>Q{ek=lQH(ceo{g=?DMx&uZxZ1qc9O zxN0xXdh_l-7>XlVnkSm7nuI(r9LqCZ+c%!;JKy`iP5~&aipC={sa!If&S$9rcu6SG ztEY}*y*TU5yZ>M)j$~<`XsR-RFc5Go&vb3yc&_g}JqUr7 za7Zi~kDb=5$80*E(5RI810b*1tkx4)PQT!=cual{tlPADZ2@@8@VI=HN{{Si7c+yFT6K@NKldesWlmQxJ6PaT!F9^9zQK7ySPGg&Q9e7d-R%a5Ze;xpA-D~mvv=TyO@o73 ze!qJxXWCqXFZxK1nrz}1;vDwO zQ5#r1XD~~-Eq0^}%3aO$AICX=D54iSO>nokTt z3wqq>8$I}Z0b_48F%Zlqz(J+pa!5g?Q0338t%XombeSE z2Qt79hX=2G8oC$Hd#Ud(zxChGSO2>7osnMs_RL@(iQU|X4+rYrk0}26PumVV_~^GU zjo>ls?S2@?Bk#NKkD+ou@y^dbUdoSqUi9{*JOAOWGU5xJ^w@_D^>K}M4lG|nFbBU{ ze2#n)^gsY{Q9(9ra2XiP;1E8zF;4WaVj`T1{A%UF!bLEJ$T%4m_7*iq6>D02(!qCh zghRX322lc2#{q8!Hq_aWTaXf0ge0;m9*!$CP#9t@7&y5UP%-`yCpaRJiloFO7NA3U z>X8;5gaau)Ak&V`RDfvUk<3@(keS0IW;(Tbo^FQohH``_4|M5`OLkxi z$17y2mI<6UIdh%zd?!8EqRe=<@|^#Krksdn&O0jLB>t2ON!`X_&wG|Lj>Qy^7{Lip zlg(3G*-WT2sq#@b>Ba)`Bjfw@FhEj~Y@||FohcFksR%Wq zt9eb}z*|<3xRHT$tzd0ydAdOeSkV-lcSDnbKvmYuB6Oi|#XyHD7+AUPQ$#iB4qIHS z*QMrxijEZ~2yk1Ga@Jv_QoRjrMIh8&CiS>@{wQu7kjq>(tZ-1xjqVJ4BVDyIwvBQ@ zWp#zNQVS?|eB1R~XfyC#ID{8tt1=lw-PA0?&<3LBy~jc z6msJ)VJt~5u-R3>oMH(ZXoz4F9*w?2pz9(a++Yt#*m%geZ!!K`;RRec5gcY-<_>&Z z{eq&RdiXFX6o_06dxOMhwxuo*vQ7K*pA&kLVHlqsxCHYW?i}+KdH<~j&)Cj?Tt->%*Whg zwKJFvHZhA%(p!dCqY0*MzpZ=1P~vvZwo7hRh+7TvZp6K@_ijIII>DYZb(-s)taDIX z75{E-zUNSlg;({|MrvEa_aM1;&zazfn0N>JjVFksz`%xZxEwSt>IdUX#~#1J!2z*v zr=t8K!F*0@VD8G8Je8z3AbI`?L_P(b3lke^Y^lt3h|6i21u$?OZ9}xHD~b0uq%y7P z&t+gJj!IpnY4z|kgV^mNaD1vE5IS-AM%c3oHlqzd6s;`&igElItjn@2D zkCV1h$D2hP19tAYvdK8vs#7B7z~_f}u?gV*hmQk3mq`KRXAAG$K3R$9PB<{;r=S9{ z2fjy4OzhRQ2!$vy-n=0=eI5R+lPZO(iP`KFIvW;cyR@7Qs=w-PUpB(SQ@~(lM?2OT zghPWJLt}`)hcq0xd1V^`?yt=$Z}>uaQf<93KkZEJ#b8nYY5~*PFS_*8PJ9*JJmNX$ zZ;?}u;FUj|{o!@LAO7L5ej(DIzs=A5{m-3AcQN1oS^!?bS1LJTciWN_RaJhcHF=ds zfV8K0sU!zfRR>sQbuzF+veXB%VSzD#f&3&tkEQ^!qXT#$e|7*`3&>8TMR=noTpTC^ zq~Tl1q=0rZfLB)ldZYog0uK4d1h;2aW~WY4CxcQEb6FX&EOGr~q=oendf@gSAB|ThENoVU>Jm4xQNk2A|{o7 zEoc)xC>^Sph-y`bqBn+j_f?8Ci>+9Rq3BUZvPRPY59mgH!?+48HC&qrRaSS6NYYv} z2!}kgiUrU=R7agO!Xi#$My?zl7XxC8Pyk1|t_&4`cE)l0V} z1p_aIi`PIRR0Ti%TYiO(lk3P=WS{bNhG& z{-^~G@iuEG0b?bKS*Mb2a{(u*gtVxQf42|?X;vq}ReZOG9hd=Kpl9`CQ@Xe$HONd~ z(vv>^*+JY0jKR1>HK{}lVT~5%c6cB^ine&LL`@Yyl_6+};K+cErx&gi4G;m99iWfl z*Fs?M0~(}%szpDWla$_MgCaO2-C#>;FojR>gB$>E&IgmRwFh<+be`ydNhn(^xlUxs z0jOwP1}7Od6IdV+jZov4iUoVrI47c=nH^|hD&*wMu?2-V49S9gM_G> zAb=B^iGxk4hxkTOXjz0HIRmy6Sg+TX?KGOCnOR&ZBDq0MU5NsC=>&TBM{zJWkSUO< z@tKubfO4>mj%kY!34wYbnaAWt&B+2(6Ofkqn;Z!S%NUMB37mIHoBUW^i@99uSzZ2S z32g6KVrn>_$aS0*VxP^$bo!}g-q)XI142oclK?6Y_~|;^*i{8;pwb|S^|_$caG)e8 zehmtt+9084`Frkgj}}@dktnJM80sk@5T6;^qB;p` zceSB3+IH^xrx&ktqi72q7Gn%Af_n<4#qY?SBl@CdfDCx* zhW!aRdZ`i>H;;AN18^Dwd)hq^2Yy{QV5IOznUFIJ-Kr@lvq~gg+RoLilQC|Jt!$R;$ToZ6d1$ zBs;IHP_GMnXe#Rj`g*b$(5f$sS1fCxG+VP*b+h~^uR0qW<~n9M{`<2J8?^N`v_xA8 z-8!GgnzScow58;;PWux)8(ru+wXC#%+KRPl3AN|eu3TFxUaK@s8@8Y`wkZR)W=nx+ z`!HL(wzA+}Zwt396J2FXx97923NyEOJ0nrsx4Ble{BpH`3#t;tw}tzM%5%4gi)h8V zG>!YMZ5s@P8@al=Y{;5Vv#@Cm>t??8xSvtE1pBUFGO&&oKaLx-@qlelCb$noWvUAr zDJwpc>!n0yZv8U5gO)IAtAVb&x*tnBdh4Ri_PduMwU<-7vvNL5D>jIWs94gwI}1a| z3pmO<0;0PJ!`m;6i>00+tQB*;R#Lt5^%>8LPvToI=S!&mn9(}Ti(K6+pi^Ty@5`Q& z1G={BImWv@>l;(&kiDdIY5*(->3f)vv%e_>zIA}WA0WM1RluC%z^Nq+3e0lzDZwzP zre%huQKUBLBg2%iNm;>yC$7-6dq(8T+vbzYJ2{BSq!r`Qk+9qQg7^v1{?$BAWe*l zos{KtnGB4Z9FKD8$#Fbdc3~!qTBK@v%8IOqH|SP>DU*wQn`_|}ogtS2tO1vNp3ZzUAr#F)XcH^wl}ret2nr>9 zivruM#UudEXcsJlESs!sgD_yokrCPE)}InNk*eV?JveQ3hoETpxZ z%HvXo@~n(5iOr_hK*NyG3N4HbeO80_(0iPfPEf{8_o21rz5J}nbmvNv7se0R1Toxu z6&j@^UDCNM#qXReV5HI(*$=d0&;KaDAO5hu;^xa2z$CE8Pmv|i&S{&z2O1Kioa-k9 z19L7>-N`x4$>lsq@)^nI`_g5Z4grV9s0Mf7x!b4iy z7$e)YjNA6oyR^;QTjCDDoifk++rvExi4hcq9Dx8CyBc{+vr5nCL?#HBkgv#u)Lon+ zxY?sp+|0et^gIRmL4ytHn;n&a{uT(vU3qLyOkLNRB;nnW(#^;19VF;Yief$2q$y#P z;nyqt-GR-JV6YG5oxvD2Q}y62v8SGHtE$PS5smFIc zp7ng-tf>Q}OV|S5scCRTLS4;%99FE1i>tiGY+Tk>J=W*v*+>(Mr0h$pxSI^Fp@yj7 zA4%2b?crDb+)4c7!>C3O)!-tX;=dH+!nn&HZcC!k5`#(CRW5p0PUK`gH+B;yGOXPuD&Zn2D^0HC1{u%SJ$Z2+&@xWb(K*c`d>eVb zEbd+AFD2PyE(Kpf-blp$8Cfo#RBndj4CrTg*l+C(JUj;ko{IBroll7AGd|^zK7EZ$ z>V3|~8K|H&I^c|akRtxacLdOL_~wC5&ak;7Qa*kMEl!E9=!2l&WAGmq-ou*C(WS2C zN6z97?TCrp=qiG^91J~zo(#I{;)Sj2z&_izp6hO2o*QlG${OqNyyE~q<=4)et9|O& z_aKuVos6u@Nu9yBLDWvo>vld}bS~oBOwgS8?Y;e4Xjnz z?;H;9l`iM3&g{)D=(OI7M?LWQjg5k*o)NE<>t5vBuIgwlixeN~2#@L^X(0fQ)pkwo zX{zr2zVhxK;V=Fl?j}Fh$o?KQLmFG9b?Bb%7*CnF4$&=7)<+-kEN}4xx*_F~XHNj) zpiqqxPwWOy^g{l~;ArA2Kkq)@%2r6gb7A$Ffb}GQ^Al6<2M_fC2A8{?^EfV^-?<5X z;or!q_Pbs3Gwa55U-w(@^kT2)g53Ajt3Y*`@H=|kn33EbK=Y0dGLk>}7lXLjZ23l@ zwwbT_n@*sf4=|h``VXVFr2jA@IXaNv7N@+4&F@Xk_t5L)sqS*zjP@FF@n69Fs&e8+ zuJSxS{rOcADd!(9QD?)u50K!WAI~N1i+yRdK^YoT`+WZJ2tZNX z3?xc9fV(Zs9kKV^^o>o}k!V_&raG{kD$f{f-*_IJIYJrH zWbDCws}@#Pgrbm>>26DQJay=_uFS4!Y3I!srgWQ{A673evg&<*ZFzSbbt8OPV}e+G zYL1T*c#C93lPNG&4UG|!AXJt-SAcJz40>V`Q5awnMuDX=n~<|Qov=f6s<(+DnX)RV zg}S>AqJE07daMzK7{LSxgo6Xv2+}@MMq1J`uV|>`l1Xa@6 z{ur|B_!H;#gR|V&JnoqocZt@&Md@hdn?Ufw9}OECK5IgcUxQ~0Gs?3#Bi^h`JuoKm z;SmzZQKS@VY*_5gJ3ACgq~ypzq(*!vX@0S(1|SNaVafmiipFOwgJ@1RT1}!vI%6tAQXwRji8EfJ-BhJ(Y zNymdd18d#-wd~8V`;AVPGI4>$8(VUwd0L}Uj++F>-ko%KisWNUm(A_Txgcr&p%FQ} zZ82~0qNy*kIPUCIbm=r~l2>iMIrHh(+tB0VdwcwP-oNMg>h|7x;C-AI;2un<0H6c{ zBA6fn#L#o#2DVT~OjY{jU>Qx`4WOZhIjpDKdvI8|p?4nIci)E^p{SsV?Fk1WO^{Vs zPIwnQ2+4(oq1S_rkKm}{it5DmBZK7?2$POF#VF$%G}gEde?gv@0*^XC*%^1Z30d8X zbPP%3lGc=%B!yup7v+ms45dal*Gb4?id!OCfKBJPxl4Xvw%Fts0QA}Co}l>YC!mBD zN>!d$8LH@_j5g{h3REJB*`t(JYU!ofC@JZ9n0D&vr=SwJ>6)RIYU=)}o{~9gOsKZ% z>Z^Ndx~iP8)@tjmpv;#x-4Y9X-17Hcef!sc-7vdrQtYqC~0EA6zF;yJ62 z)Ml&go~r69=Cs-yd=jd>k9MD+0-oQW*T#VG0s3Q`0me8^~`C|NVkFT!$NCJbkb0-V)Rox zPTg13SkEByl4NYnbk<;xuymeJW1#cJVW)jT#GA4)cFStVZT@vDV9m|Jw{ds;Hkg9! zy>s4JpN*)?BzR3W;83$IX~|RCy+PTC@9Q`;miRq*=AdJ^|jCgKN2rD0?1B z=pK(=A>p`~P9*9KtF9mCA-WFx!h-+ZpzE*S9&hfKPXqj@zW?qy?OpNSd-2)It{>xU zXpSi8%){!ue$-Q9!di{5-%cp$!-Ipr8jL6rmeEQ{gdj95 znIH!b2_w_O$Gnhg{xO`4{vK$l6|zf&IV6J*S?DPP zjtYoD49E?ahbbc-F^SV~BADu?!uL^*%aAk}D7ax_zp6#)CbW|g;+PJAdMh*Z{Ton~V)yJtBGHi&< z;}x4lNJXv@Xljxq45!sdyFKz`k<{cQwN=Svy)ky848bCCmB_gX;F8-4Kr8Qc%2#!g zcLS&;vt*e{t_ZA@M$09`GTBQTP;8d#(`BgcQcN8v^H<2c;X#1K%x3NiX1BDaIbcbX zyF`VMbE#qhC}Zx4m$-l&V2e)lKULy zKL<)s8-#OU{Vb?L9qBuDF7%<2dZx*M3DJsL#g6n#s6{s#mxD&lp&SjVBP5zNjf(W7 zRk~wMP|8vnVN|7W0clGsN>bm2a;7+)MNP|h)13O$pfDApOn+*{o#v33L}lqqgIWrT zCe@EjwMb8&>d&P{wVOkwDwvFV)%0k!jNIsIqj>pM&k0kk1aoRxaqvpCo{Fq%l~h~Z zI>)RMb*^+ZR#@U%4L0R9Tzlnf68!qtiFvcE<|u5`(kaqyDi(H(Ehabc`q-o11u#9+ f&}z}*y*TU5yZ==%5M*hdXsWJk>ym>2fOKt#Z?5lr@0)>} za0nRvj>x2PNeT|14gqs|iUnp+KtN!mG6m3%)TAAU^~ClQMbD}V)!ktPm(B>t_q<93zD#q1#z*n%C}Ra%Focz1+dLDzXhSgln~hpr;iQSsG1Pp zDv*+$vJJ?W4AfsWF9NyRJGthm3#;S8<=eghdK1X6Q72>lh{;*!LEJxm4+x#fN3IeI zMgqfSycYhf61)<<0P2xOvZSDqH9FN(Kxkb%0?wwHh^aDSGK>&SWmGg1MgvQoXfR`f z5X6?DJ5}wWaI}R4aXVu68%V%Vi69O^$&ulCzDn9TE4yRa+J3dJYr8en?msGf# zoJ*Gm*(G4>>b>zX3532%_6i;X_z1%Wg^?T{%-F(0t$O4(p1k0$l9d+_`J>F(@?{&I z<8hXjIEiGwnt_alf|N|&H?1}IT5U7+(!sH9=NJ%!9wrT#1aQ&a<23Ei#FOiuP1{Ck z<xKp=|z5JZ%;x&9X&%TFt?(5sj-#QsCb~BX8mp5)F z{{9l?>0yu?6^q?4AQSurNP~YoBnTNIU_rIfZD>_gN--4@@ZJr6pjR786-b!VRGCa9 zl3N8ZQ{WrO`LH5ler!O9TrFi7g$iM92FwYDzyb|}F1&W&4+<8E#*jU{7~&3qxaY`( zGd-kDV7;g{o(U5u*62uf6Wr#H^d9{v-#f zjy6jHl00na?6eo)>H@W#SzFeJu3;;fwkqff>J;9Z1a7$M`Qc!>H?-)(x)Qi+7`snE znt_}g;F)+Z=Dg!2V1<&>Gd=UT8@OB4BoZQ6pGO)14>L#4A zG+JCI+o>Oy49pf>@Mc`ZMD@?gEU#i*_9Ntd>#kFFBo;RL-&f3Jc{gijN2v z7NIPy!NZ((0J;w74GS!Jn7M|@*3PAz(dJC*&z+y8-1XpOg6gEP2DH8NrG0hCVEy3MY7s0J2btOI$$oq_{gRkpcdK;oFV_x0OX|wXTcJ z`l9H{kSUnlNNf8bqn{eIDHn7q1r2m!L*!s54l)2`!m$V%g$OJN;BiH!gWXl!VJMi` z>RHROf$m~ZIjZ?_W;Pt4`Bo>Ub`;VLhn&FOsuBpe7$=ht@MIDNB}j6tp^0%q5e7E- zH@ziLV`n1)Am#VU%EXeBfEr~ZE5eK#azKn-nI8;D7D-~kQe-e8=H!rAxFsIMmmAn3 zy1+=S`^Au&)M6zzsU^)6IBuJwBEw?z@J(=LMiddS<}}UOH!|4ob?g)Z2uZi3M8&@g;7F7<;OGR>n>e`W2bZY&Z@ zfr^NjW{apkGpfLl$}n^GjHycKY2IcE)hej(pmy1U&yf!j^=p&mg2Y?x4!8udEL zz0Y+{YT)}a{Tg$Xve6|01H8hu6pea>41+_HTShr-D3AuEod8jILRrknVC3|GUyGT< zb*647>R97LJ2|R;vUisnJRv_w8ATPtq$ZotCU7WMPf6;q3vYzTHOA#%M6m&jJnnIf z0jQ5PRPaPd3wtw>t+k?i-~F0Qe>X zO5so1{HwdvaC4y`a5ULq0sThJJ__9a9~9Ti;Sqf}N7!Y`kri#k9jAB05a{Lm9-Kxr z&VsHldNUF+pxa~y3yF-Y9a|!eyK*^H&w)jQrg53-#yGUqlnF7c8S`o{ams``sE3sZ zP?SZuFNzF?G#p}6Tsjdbe*v9j3+k|I4Y#j23q}F@gqM~yyA#L z+=E^pB@SLD9P6Udb5tXt@u%=6Te{2$Z-kS}1j9es_}E8uBfqzlae!=j-YD0hz_;;2 zx3EAdi;{;b!;Os;S6nP-?qU8e#hr7D?{}GE@#mvv4(_6>yoeqzIuuV~XB?WlQsqXc z%r{N*NuSWz>}KZGHw=+rn4u29rD83n?(V9msCq{)FUD`~D@lvp1t(88$U}Z$rQfmC zX;-_}_g-*GhPo0W05Z@PXU|#VrtpT}i)Itg7@;#h8jjb6Zew7KQHQeBwnQf7&lo~B zW_X;5vh}s89J+Hq-RTiNJAOZ2de0M@TU6f_pKAaYpb45!x#-;6Wm$*Y@7(NwvNxUx zL3b+Dk?(sk{ap2w@_=S*>KWW}-jJy` z7St3-;^4R8*=Ah1CjLOFZ^YxFG?QgLulsuI=l6;iHev}_fGqS!YB8s3$Hi)JZ~_oC zSKsz~b_ZjM;syeUatJndcraGn;1J?~RvV~uz$ZcNpdVF2bhq*tLUDTP7k?0_cM52F z-4=lX7eV&6Uj=x1WJ7v8Ac6I_g9@f>6s1D2@MN*)X4EHUEubrRk{C)dEF`x?3@C3y zcYu#q7n+4?RTwEKn1$7Kgj{$BE%t>bp;?J0h8e(SH<)*e*cjo+f_HF^!dF(hQHE+DS>;F)-WY|?u#KJ)kJh7(&)8gRgO94F zkL&0)=8=E41s%os1kTk4?Ds9^L5<4NTMMZ$z@;4SsDm=|R#~7`5p$4m1CV5MH6ZDc zNWhWLAd;)~E<$yZx7953sFJznEhg!bFX$~TDU&eak8@FzqeYM=(_J=M95^`|2{|L2@0KNkmh%lgM%_Ea|E!pmDrL106PaV B-D3a% literal 0 Hc-jL100001 diff --git a/doc/images/cups-small.gif b/doc/images/cups-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..6adb4a29ffbd6b806d8eed34fdad33f6138e8890 GIT binary patch literal 1266 zc-jH-1P%K~Nk%w1VQ2t*0P+9;%*@Q0nVDv0W-~K000030|NsC0|NsC0A^8LW000F5 zEC2ui0B8Vv073))Si0Q)Fv>}*y;P9RyZ>M)f&+k^&M>Z|5CEnF2ZGAp#DF#d?g_gf zMB^g>Geuovvm_`sy(66bkjl^nG{>zj(HFtg+CH;@**F8gro_jj zgj?4byer~)Nf456i8gNvL_|X0AKjZb>HiP(?JJY134<#O)`DciDjrm5wU?-9CnKXPnbDTvVa3|4f5K7S6B=AM! zSYIVh=MMvpL6%}^eK=5Ac<_z(R8;T0D3mP`7Qt9sGhSe$EOS+sTM)thaLtgUiD6_2 zhR`Sjh1$62wZ88{PYI*?4fc95P!hd?1I4wU9X6lPAS{=i&_ zo?VF1doqTGo^>DAmj)l0_Jo62Oos5|L@{Wf#B=Lafe9Y8?x1TS<83QJnBi<_-$QF~ zvqbn}J9Ra2PGl=fQ*CO_rXl%ZbOXykTl6(kKS27Gix4ug5I1RZMXO zBbFK{-Eb^oSCF{BD!VbP${lImYwjA1)NIC4D-y>1WqfmY9^86Ew$5hPT}r(E%AOU% zhC(C`+PyIFy&mz^)!zKG&baOq|v6_F*_C|4I;#4HBJ&n(8w@p2}RL(2}!DTz7 zIG=4kc*1vOOfO{;dR^(rrfcEDoT>YJgRMGB_C>cOroJw|OtX+}?8J8AwwtsUuK4Sw z5B0$9=>jZSq?PU7mVgl?>3n3RM_&Z&00rl%Ljuo*JnjL4`dgCQKS1hOMq(ehtE`8? zrH@~CI=#Aew*Nrz)z~kCpmbjemmzCuiKEn_sG606e}~$YGVqr`cF?JT*DDeP!%`*$ cc1nF?aZ~|iF+YF}&@50&%OUg^gaiNpJ5-EOApigX literal 0 Hc-jL100001 diff --git a/doc/images/delete-class.gif b/doc/images/delete-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..81b1465acdd35559182b55e5b98ade10bb0afcdf GIT binary patch literal 259 zc-jF20sQ_)Nk%v~VOana0KxzO%*>g9fM7yGF&G#U0|Np800384LI3~%EC2ui09gPO z000Bf2)ZFdCCW*wy*O)0h6qc@3|ncQs5O8hV5D#?TZZ_~c#hUep#Q)Oi)1+%jhX{S zX*x0sPu&3EyF{ZE>_ltbM!2)alJY!C%1CJ1ob7(o?=3ju7<-}TuYS)gw~Kptf_;G% z4|aKigMoyKT40ZbiWmeCZi!BfnS4%vo}F=La|IoUe1DOXo@9)ycPav=ey5JKs)d@E zv~wRzprW&CXm4}BXi9xoqaZ{<&dyU*&(lCGF4WjEJPSA3-W%H?0nOj#5-Tm@4wmNA J9Umg9fM7yGF&G#U0|Np800384LI3~%EC2ui0ABzU z000Bn2)ZFdCCW*wy*O)3h6qc@3|ncQXgPo)V5D#?mxlPxc#hXfp#MM=i)1+%jhX{S zxj7;$%%W@n@Li$>EOc4IYLl}DcM?5H%1?9lN%2OM@b~(iX2&m%@mbDimiv2cWORLg zfQ1Ybh&DCpHjZOgv*f^AVfjc))Z7#*W1@DF5KWcJPSAB<|yMK0o3R1 R7Ar044xH}h9Um|NkNW4ozWXWgvHHbZ8()Nlj1yEC2ui00031 z0RRI2jE||y?GK}zwAzca-n{z{hT=$;=82~2%C_zc$MQ_q_KoNI&iDQg3<`(DqVb4K zDwoWr^9hYgr_`$Tip^@b+^+Wv4vWX+viXcotJmzd`wfrF=k&V$j?e4&{J#GW7$`VM zSZH{Nn5ekO*y#8O87VnQS!sERnW?$S+3EQS8Y((UT55WVnyR|W+UoiW8!J0YTWfoZ z+W?T;1mMf7BmGNVZH=8Ry}e_7?TrH-E?z@kZZ3m9 ztq#Nf?EV5C&@Ioht6gt@kMirBfM357&*B9HIFQ7$eGCL9{NQjw#D^K^Jh?ofCY<;rVU zmR-@ecA?_j>oROZt$_CtMru}U+Q4`V&;09Guw%q}88@Cxd9hW=nA`R}xVE!r%bzhD z{zuj+=fd_LGi*M<<1Jrg z9bM+0O};_bTX;Ghh+ka76(^v7H$6z)gRxP#8gdSDHl2k`NoL(^&h52ah{Z{$TRY`F zMxZ+!%7$KaE&c}-ds)o~4S)SDrV@_%eRpDy^`W?pctL{L6p{29x#NiPsi@$JGS2uU zl|{Zc+f@xFCuEmS1{o!iNqXobGE0%ArIOSD*koTG{`97oR(|-Uh_z{WSDZtZ8K#<5 z(l#eWhso)upn5uoXP)y-^=4N%u9c{ZWI|f!gq7~dqG@1~HkhV%TG^;=7KSQng?x&Z zA*rQ087XU_sj4ZXr+T{Qtg)WNrl%27wWY2{_Udb!um=03i*LUA z?#pk#{{9Pazyc3UaKQ#2jBvsVFU)Ym4nGWW#1ch0fMCo*G0Yee%mV_<007KaLI3~%EC2ui07U>4 z000BA2)ZFdCCW*wy?Bx#!urgRjbu3v9tap_>$(QWzI1)XN?`ANl!}%EMR*}jj6n?Y zG63j`LuF+dg_0W5qvXKdZiQ5BglhzcC627OP#(M4=XV?awmg(%a-GOuTjz5Y1Q1qh zfO{Eza()#XYKxG8eu`{}OahOUnwpATRh)*D6&;yno||1^dS7j)79K!7vMx?47M_YOT literal 0 Hc-jL100001 diff --git a/doc/images/left.gif b/doc/images/left.gif new file mode 100644 index 0000000000000000000000000000000000000000..fd7b0410439bdc234c3e56e5c41308dd2834437f GIT binary patch literal 110 zc-jGO0FnPkNk%v~VGsZq0KxzO%*>g@#F4YJfTpH%o}O!&nP#i2c(=ENEC2ui01yBe z0009!2)Yn5q)5q{nV7DV`x2c8aADSz-i2bpnt|>##8X7yIA+uH4b!a~KovXD6eQQD QxKT0!L{Y^7$s_;(JJ*UWq5uE@ literal 0 Hc-jL100001 diff --git a/doc/images/logo.gif b/doc/images/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..9999795caa725187141a472f5dd1109491286b8c GIT binary patch literal 1958 zc-jG`2U++>Nk%v~VMhQc0QCR>@bK{O@9&O|j*E+not>SVo14DAzPr1-mX?;3l$2gx zURqjOYHDg`W@dJFc5`!c2?+@W1qIX7)6me+&CSiq%F3*)tf{G~!^6YCz`*P4>+0(2 zqobpsprGaD<>ch#`T6aBzr-i0J6(DJdx+ARyr2;N0BY;^N|_rl!cq$W>KU^z`&HGBUBT zu>b%7EC2ui07n2Q07VA=z+G-gEOL%WWM|22b_md@lu)Qz3#+VFi|Be0iEudO3V}lC z$#2d6q1ZbBY~4HjZnj@Wv*~YUe;$H@AB7$tHaLhjjEyHZCnqSA5)%}b4GsXC0c~s| zeHtX5EHfwq0~{V45DWu93MB(L0|_<)IvFi8J|_YtEfNGRE)~WVIvC2z2F(W~3J)59 zeKXdBGan9gJug2HjSb=rEEtfI5|tB{6vrt&${88W2G1lV1V0=;{1z4$7l!PJL1@vU zMvQJKjC3O1oC_4%=|Hv&1HA*!o|P!U&xgN{L^yO1`Gg9W1Y|&{T*(rRO8`80Y?8UD zW&i*I0%*{wQ-l6bKGv?y7*r4k4n{{CK{|(mfrAh+L*Q6L0N@ZCb7cIG;3L8h7kzsC z(BR=3whxC6B~64-;W>2bA|9iNArsF48+_*VV~v1UHUd7V_#q;K3akQbL>OV?0xSs; z7QA_|4Z(;M6f*o!u_HnT4D&KzBte>E#|00DnmvT}gHfbwZA9`)VG;wv5n52#WcbS@o=xDt^i`z)^>>3gOZQUL`zB(qF2SmN~IPDtX_hYP>;;Q==@OqD8^!NLzUm_P#!6+l3P06(;Fn|=`-zzPX9&``n; z{txW%f(0tnV8I9rxF^y;s->ysQL(uN3Ab&$@Yx08`EUei_;gS}4kd7aKn^DGvw{FC z{4>A+IjkUq3-Jy>tw(H1G-jZku&xLYuY~-{1Xxr@MYnJ2{;ST zu~OVcVygtWB16}mp=t!IN5cjrFG*0WfQ1+d*eCVG7t5f6g%@UxVN3u52vtoV+5{q! zd|6YbiT1JvGC~zfl8H-DneYSt4V!%J z04^}d(7_KFRN&Jc3-qucAWHTPVNxruK8daC$oV==JVeX+4*|q*2Lvf>0D}S>)Bpnu z#vZ#Q$Sc0(Gs)}-olKrJ*#QHA1@2@w-hjZ+f(L<+p5|*#Lg}U?l&F$ijPWT9UQ>hflHDp-bRo|?44?o_i0wdp%F7HE*n(ZG zfdnvMK#eeP8yB=7H-O4RaehF72)IB5Fn|mUdLRP`JOBnFNLf5aI2vd;ASXNF$zJ}@ zhZ=lC6%KmA0uJ#58|>gP5U7C-p!0$gydVNP^4AM?aGMEW;0FmP&8PlCMFOMwpoBe1 z5ZS0Ghz-2sFDmeW3PjKW8%#h17Vx47Y+!&9VBiEJNQVPPP=FD%Km;wQ69+~h0us=} zSLZpJM^Mv~891&%R%8KdTqOfG&B`scq7pkOFn}G@X^9uX$kATr1Ay${0ehLCYKBq> zE3%;lY{`cw79fG|rCgU;zpkK@b1{JDeydnE(I) literal 0 Hc-jL100001 diff --git a/doc/images/manage-classes.gif b/doc/images/manage-classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..69d5b0147068125faa07a4a84266a6d81aa269fc GIT binary patch literal 289 zc-jFW0p9*cNk%v~VQ>Hx0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0B`^l z000B-2)ZFdCCW*wy*TU53mHPNjLguTXsWKoAd-N=&UCFBq-^heFX4)SZ%CZIOqN5k zxH&kL5h$}V00=KmN_L8!K&9MC1GANspXNeYz0OL}6|mRb2G{L!ii509f75JHf`eaw zgL6xLgo}!Aj1~`kj(LWPh>n(&U0R2onVuE|5SvPsPo{KRn5UYFY-f0>uo)kGeTJ)m zxsR@#pNP7)kOIQHjlqnnfWFDdxQEXdA;rsRrPXdx*V=iq*xPkp;TR%FVZG-yRaWWM n?K>|q@2~SUKnptc`YZP%0p|MxW^e(+pMy~X1%3ztBLM(A>uiRu literal 0 Hc-jL100001 diff --git a/doc/images/manage-jobs.gif b/doc/images/manage-jobs.gif new file mode 100644 index 0000000000000000000000000000000000000000..adaff856f0929ebe37519e68994a60a767490353 GIT binary patch literal 266 zc-jF90rmbzNk%v~VP60g0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0ABzU z000Bm2)ZFdCCW*wy*O)3h6qc@3|ncQXgPo)V5D#?mxlPxc#hXfp#MM=i)1+zgD~So zi5dWWOJ?LCMV6`)Y^i~vQoK`e!6+V=y-cb$D^a)2*>%Lx9lw?7@O00|s;R7(t)h(<9)X*+o~vM! zv9P(V6(6*^Zm6TfdTF4XQkr&WkRU`>SJF*A)WO##EH2qa$=ww^3pe29CgLFh(dO(F QD=p~`mhIggA1w(0J8!smBLDyZ literal 0 Hc-jL100001 diff --git a/doc/images/manage-printers.gif b/doc/images/manage-printers.gif new file mode 100644 index 0000000000000000000000000000000000000000..cd897291dd439440a3c86a2b66cb8ebd6774878e GIT binary patch literal 296 zc-jFd0oVRVNk%v~VQv5v0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0B!&j z000B^2)ZFdCCW*wy*TT=$q>OJG6QFxXsS{}I0D8h&$Mieajow>bt{3Ma7c5NEC(b} zb7(e|m!xh02u7un=MsZ0bT{8wgZtHb%}MjQ`@}k-5oy{RKgYH2x;#8_aOrw=f_Q>} zdxc?acY|_+S&N1k4}Wfe6ODzBmY9}VPL+V0k^;fQk)g|kna{49%(KuEAjz6*yV-AtZfe=F(~z)id=eo?TN&r; uGE`OW#o_Wr3pw?#`8q%M`~N%oi3p$$pg|KYUJP__>Yzgj9zeWE0028T9*5-s literal 0 Hc-jL100001 diff --git a/doc/images/modify-class.gif b/doc/images/modify-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..58a0ead8297209371b80fcbfd0ca3cfc7513fee7 GIT binary patch literal 267 zc-jFA0rdVyNk%v~VOszc0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui09ybQ z000Bn2)ZFdCCW*wy*O)1h6qc@3|ncQC^mp1V5D#?V}|(7cn;S}p#Q)Pi)1+zOU6P{ zxy&4%%Vur>@Lir1>_#fZG?QIi!^@3oBUmug7_Eer66oa2%s9MobiTb;@8fP)dV_v` z77uuBhKq!Qd2@nUj*}Mz5Rq(+ntz;OZ)Rt7bQK+VaD{-6sCu55sjrk19;T{}g{!BL zntZEo1s}A0Yjc^LvBaTqX=q=*1t3I0Thb|1Rn!{J*cB`;+ehCeJPSAB<|gAI0nz8} R6e}(24wvrV9UmglrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0AThCh_ApzO&_8KcK^A4i-{v97$Bme+At6qKs literal 0 Hc-jL100001 diff --git a/doc/images/navbar.gif b/doc/images/navbar.gif new file mode 100644 index 0000000000000000000000000000000000000000..c19f634c0d3278ff58e20c19eafe9136c8bbd5e4 GIT binary patch literal 2869 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 Tn1e`|gi81agHQ-67z6-28w6=Z literal 0 Hc-jL100001 diff --git a/doc/images/navbar.xcf.gz b/doc/images/navbar.xcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..28438a6bb82303522c41ea5b3ce198a9de9a23bb GIT binary patch literal 4253 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 literal 0 Hc-jL100001 diff --git a/doc/images/print-test-page.gif b/doc/images/print-test-page.gif new file mode 100644 index 0000000000000000000000000000000000000000..807dca10e6c69e9e2eb439a00057365f748df68b GIT binary patch literal 288 zc-jFV0pI>dNk%v~VP^mo0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0A~Oc z000B+2)ZFdCCW*wy*TSl$q>OJG6QFxXo?Qu2pDQCuObgu7_tpvQFP}M3~4oKt? zbD$)jrlu1*8~}h9X++E6PP`j17p!YAzuQ7nx@IdY-sIOEM{nPEwM33_ocDQpYHVps zfQ5vDc8G^=g^CpqOjL@Af@F|dmXCXscAAfv1q2XThL??|oqU6bi&Jl)gRB)Ee@>~4 zr;xb3zLlYz7$3KbmYc7#iDIYA$9-74uFtJ-uydWga7vDvcorc>L*q1}kw4_=D6$+a mFY54N-x@v(IPv&2^&$b{`TrbPxZvlY6u^TKJb-YK0027`?SZ-g literal 0 Hc-jL100001 diff --git a/doc/images/printer-idle.gif b/doc/images/printer-idle.gif new file mode 100644 index 0000000000000000000000000000000000000000..68d990c628dedbf4326390527ef72f2e90aa9841 GIT binary patch literal 706 zc-jHN0zLglNk%w1VOjuC0P+9;0RI40RaM~N;Hs*s0001gk-vYDzkiXxA^8LW000F5 zEC2ui09pW0073))Si0Q)Fv>}*y^CnUxh7pGd<14vpEz!6>%QY4&ve>uB}(tM*u$=0 zh~*0aj!0x6HzDkv(CC0T1OcxjAXDO$YNXGu%!(~jZg(+7?vyLqy7<$y%2h8}_!c5O1#O@a zR!WRP_!jAB`?Z9$cdG_4C31H(A zdizN3T)OVI;oZx(uiw9b{pt&>?ju3M1^W$@co=a3AuVIfv^w~$y{pB-h-^IRve9Bg zZG=2w@aN}0nh$QUqw#^j(+Ej~1F`Ce!zK{J!PXLzHp!B$F;!J<`YG|1zggYpvXeMA z%FvQ4S$-^KZ{23iki0V_sP*gF|CtQpooYbnMxmBBKcy4M-C5$iA{&z@e5CS~(%)GY zwuySBIn~$SY5(E223JIZ}*wI++r^T@^^jv{DWCws3gD8=aCR3G_lbf6jnVq1aqNAh{ODr@msT`{UV~RXa zb|9cdbtSI`sH!zhz8kV)B833O#aR`3i#xZty1;+Jjb~JacFD}j%SVjU-XDP2+p*dK zeBV&f;AMi7hp^*EQtE!0h@tlH+VmOukfogbDLI z6u`|b))n)fk!G4+fU%3!vgav2879Rp@fd}_GxTc(nAWJ z9e*AbdbDXnrc(x{OOD=pkAS@z@ztpvHjzaIt{&cubs z;yQA&y$zTrab7GZzJxB>Y%X@P*KC&P^ZNDKs^mw4WnkgPw59do|` ztnAKQ#LZWp6HV1LR8dE*F%mz^4M-q^n;i&Mf~G9fl!MTf#EyhSwRaa<3^J7lTTdNh z%^4piRp5wfVPaQVUP*`CTtSe9RE%Jlg9c&fOqWb|IHpA-J2omv4vx(1HDrx+q^Kia zN-pVFlQ8DEjgV3<=3|v_eHCSoe{6XpUdmwk4OX+H0HlgZ#&RZ!b+tnql6tx62V<3$ zl0{-@Y51l+0YS26pFx3HS_PT$Ne-T&dFD=JS87$6WqL+-)>fQRijZYxrqk$Zi86!B jr?YWNDsBxl`U$Fts>&*41HCGWVY1e0>#evxlmGxb6oz`@ literal 0 Hc-jL100001 diff --git a/doc/images/printer-stopped.gif b/doc/images/printer-stopped.gif new file mode 100644 index 0000000000000000000000000000000000000000..76f45649b132bde80d5a90530f0cf990aa4f5278 GIT binary patch literal 794 zc-jFP1LgcjNk%w1VOjuC0P+9;;Nak@s;d70099300001gk-vYDzkiXxA^8LW000F5 zEC2ui09pW0073))Si0Q)Fv>}*y^LtUxh7o*d<14vpEz!6>%LuB}(tM*u$=0 zh~*myj!5JnHzDkv&}e`-1OcxjAXDO$YNXGu%!(}weV8v8{Hb9z$++MQBS{AMyne4< zPg!tsf`dqaWG`DLdy9O1et%1cW{D@23XFLUVl$E}mY<-ZqN56DR9c&K9d@8jryiYU zvOce{9C&d{6`PNLh*qjAvjj$XH@joJy)|yLZ(7L9e^IH1F zLyI0wx-^8frUUk5m6{($lP6iX&TwkxP?)kaCyX2}-JSFs9tCLZ!0u1?hk zx4T9zA5O7W3S386j!j09Ix3mZRpw$`N+@{m&Z!V1q&>o0?%loOjx9b{`_quYOaEm? zeBmB*TIHu7fAQF47gS^=HD6Vck>^l?Vfa!Pbqz-Mo=eSm=fP9kC6i!R8dex!Qr>`w z9*6ENg&|ewfq>OPD^Oa}{c(S6uiji|^0mQ_G<_92nSAtu+6 z!Xz0%BoKbnq+e+5r`BDI%qXK(Sk8qNLTowarFngYDGoeAaEaH2Q@|I9nu$$_A_SFr zxno678s`-Tl`Rn=T!+QMrhK8~IpiZ692QAY4l0u8RvAT_sG=?*I$EIbHE3x=j+G)2 YPqX2ntm^8kuqFTiJFzuv761SM literal 0 Hc-jL100001 diff --git a/doc/images/reject-jobs.gif b/doc/images/reject-jobs.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d938e308475bdc9862421d2d21653ff105b4b3a GIT binary patch literal 252 zc-jH{00aL=Nk%v~VN?JV0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui08{`J z000BY2)ZFdCCW*wy*OhsL|7m*Xk=-g*6@XZfxd8D8KEoRxJfHP?*Et7$Z{waGY3=> zvn0X>fZnB9pyI3)tVBy{Fegppc6%f*#Z&XR9AR4=-*HubrrYD;c74uIL8eA|ZG(M# zU`T{~f?N{>e@=;kdy?5_ CZED;A literal 0 Hc-jL100001 diff --git a/doc/images/release-job.gif b/doc/images/release-job.gif new file mode 100644 index 0000000000000000000000000000000000000000..a05cd9cc7178499b395e08d26165b3e4a55adabe GIT binary patch literal 255 zc-jH~0093-Nk%v~VORhZ0KxzO%*>g9xnM%6F&Li`1DOH0N=$Kp;oL*3U;!!G@4w=Q7lH5t>$WadM2+c4lubub=v3ks-8Y)^Y><55f4pA zd4PL=VTy@@h>wgE1Q33ThIe#^XLX!oa)*Z&9deL(SAC_YkeHDZ9;APujkB?|i?x8P za8gCLo|bE4c4%*H#(c#SAVgWsIZ#o~(labB)7LvT*xML9A_2_Y+bb<04TR!Z9UmglrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui08s!G z000BV2)ZFdCCW*wy*O7gL|7m*Xk=-g)9{6Wfxd7o8KEoRxJD~M?*Ek4$Z{waQHN3z zvm}xRfZnB9plYns3|6wOG?$}%f0%g-h|3pUWz71AI9#MaO%EZGi_+&&y0EC~QRoy%)n literal 0 Hc-jL100001 diff --git a/doc/images/right.gif b/doc/images/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..8ae8213ceaa55668ad026fb2b09254c96ab59dfa GIT binary patch literal 145 zc-nLKbhEHb6kw2Gc+9|X=FH3^M<#CG+^}p}@w|E2GiRo)UR|+$dkc_(6)FB?VdP@q zV9;Rz0+1ODEOr|_Jli-FvJG~d+<4a8Zc)`#HtD8S(z^75Lh&ne8~hLZ{XFpC{PoW- eYqsCz@mxK1*18bwZ*%53NM|f8I+>=#U=0BM(LkI4 literal 0 Hc-jL100001 diff --git a/doc/images/show-active.gif b/doc/images/show-active.gif new file mode 100644 index 0000000000000000000000000000000000000000..d232ef9f84342b411b132828eb6cdff279469b68 GIT binary patch literal 303 zc-jFk0nq+ONk%v~VR!%(0KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0C)ft z000C02)ZFdCCW*wy*TU5F&RRzjLguTXsWK*Ad-N=&U9@@1}Wcs?^`)V;72U-UZ%@o zd5|=H&&)GAqf)G#0br<{OrZtrwI`00H4Tiox%9Tf&Ul4=eKXNk%v~VUGY50KxzO%*>glrgMjfRC01ZXJ<5KW;2nIUjP69EC2ui0FM9^ z000C22)ZFdCCW*wy*TU5yO+cu1WU;bU#hNb%MPRo7;bIfxM!Gj?*Bm7P7w$ik4Q`m zbvZZ>5@_xzwN)!uOqQ~Zss?~!b0Y1suI5xaP0p-W4Xp+0B-aboJXd?i`~QA@d3R3{ zg;8{Fh8$+~jPmYWzM&9A(uiCbp0$Hv5fxY)PUlBojI)xx{knA*z2 z?#AHaqwf_Xk*w*B&sc|}?19hv5z?249~xE!Gmv1CBnX>^Ho$~|=#Zk37&9#Tc&Hyy j#gGL(I*J@=;bVya3`wfA2t&q62ftRz^bul&j06BXGu)o0 literal 0 Hc-jL100001 diff --git a/doc/images/start-class.gif b/doc/images/start-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..2b6f43fad34cf9d50e46ca384a87ba7df433d834 GIT binary patch literal 238 zc-jH(01^L3Nk%v~VNL)P0KxzO%*>g9reH#cF&J_Z17`vNW&l@_LI3~%EC2ui08RiD z000BK2)ZFdCCW*wy*NuUL|7m*Xk=-g#qfoIfxd8Tgl=r#+N=b4?^CPMUZuY#1D0c8r05cbQa$7af*)oPV04j;4DR9&bfQRbfVwcddc2bgmg6 oLR`EtP*J_XFDos=#yK>{$`m>w0lUk=Dl8xkebG1^9xMp}JCE94=l}o! literal 0 Hc-jL100001 diff --git a/doc/images/start-printer.gif b/doc/images/start-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..017bb394aa59c23ee9b7b7058a49ad34c62840f9 GIT binary patch literal 255 zc-jH~0093-Nk%v~VN?JV0KxzO%*>g9xnM%6F&Li`1DOH6HT2X1t~bMr+JEvxO!Xn{FqM=W_b&#yGyxH`0t=@8^ASfq!%< z5E^u3eQjK7i+Y2Mj9?N3hf0rfONvp1o^zTS9Aj*dlYeY}r;(f(9i*R|kDauutFn?8 z9(ajwPH;$hPoI;%xELQpK+8W=Rm{*iD=pF0FFOl1*4r4^AOXtU;wmiP4wvFU93CtQ F06SU!YOeqQ literal 0 Hc-jL100001 diff --git a/doc/images/stop-class.gif b/doc/images/stop-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..5cb7adfd808058a01d565fc69abd5c96e0114cc3 GIT binary patch literal 245 zc-jH=01E#{Nk%v~VNL)P0KxzO%*>h0fMCo*G0Yee%mV_<007KaLI3~%EC2ui08RiD z000BR2)ZFdCCW*wy*NuUL|7m*Xk=-g#qfoIfxd8Tgl=r#+N=b4?^CPM*Ndr@55+lW<*U|+azvpRL;>e)IOgOr`#+u`JyX8T8>;DyXfp>5j z1P~>5OMn!DU}2AHhC*ahcZ-B{Qh1z%o)jHimU(h|qnDYeq!%7;kYiq$Z-K9iUsP9X v5g(L2x>+PoP+7mg87nP6#l{vo3pLEq7|tL8z0%SuEY%K(*ghN{EC~QRBm`$i literal 0 Hc-jL100001 diff --git a/doc/images/stop-printer.gif b/doc/images/stop-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3accf3dfb2a3157d04b30385e2b0e11e6b0cb20 GIT binary patch literal 252 zc-jH{00aL=Nk%v~VN?JV0KxzO%*>h0fMCo*G0Yee%mV_<007KaLI3~%EC2ui08{`J z000BY2)ZFdCCW*wy*OhsL|7m*Xk=-g*6@XZfxd8D8KEoRxJfHP?*Et7=yE6?B*&Ps zXh}9@13-^BNjhKGD@luLV7SIeSX^LMvgD(+Y&DO|@QWj3Mw0LDb5*=%?4* CJ!;zk literal 0 Hc-jL100001 diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000000..f687fe96bf --- /dev/null +++ b/doc/index.html @@ -0,0 +1,36 @@ + + + Common UNIX Printing System + + + Easy Software Products Home Page + Do Administration Tasks + Manage Printer Classes Status + On-Line Help + Manage Jobs + Manage Printers + Download the Current CUPS Software + + + + +
+Common UNIX Printing System +
+ +

Do Administration Tasks

+

Manage Printer Classes

+

On-Line Help

+

Manage Jobs

+

Manage Printers

+

Download the Current CUPS Software

+ +
+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-2001 by Easy Software Products, +All Rights Reserved. + + + diff --git a/doc/ipp.html b/doc/ipp.html new file mode 100644 index 0000000000..6a468e4f9b --- /dev/null +++ b/doc/ipp.html @@ -0,0 +1,1434 @@ + + + + CUPS Implementation of IPP + + + + + + + +


+

CUPS Implementation of IPP


+CUPS-IPP-1.1
+Easy Software Products
+Copyright 1997-2001 All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Overview + +4 Operations + +5 Attributes + +A Glossary + +
+

1 Scope

+

1.1 Identification

+

This document provides an overview of the Internet Printing Protocol +("IPP") version 1.1 as implemented in the Common UNIX Printing System +("CUPS") version 1.1.

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This document is organized into the following sections:

+ +

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Overview

+

CUPS 1.1 implements IPP/1.1 and the operations and attributes +defined in the "IPP: Job and Printer Set Operations", "IPP/1.1: +Output-bin Attribute Extension", and "IPP/1.1: finishings 'fold',' +trim', and 'bale' attribute values extension" specifications.

+

CUPS also provides 13 new operations and many new attributes to +support multiple IPP printers and printer classes on a single host.

+

3.1 IPP URIs

+

CUPS supports both the "http" and "ipp" methods. The following +resource names are used:

+
+
method://hostname:port/
+
Can be used for all "get" operations.
+
method://hostname:port/admin
+
Used for all administrative operations.
+
method://hostname:port/classes/name
+
Specifies a printer class.
+
method://hostname:port/jobs/id
+
Specifies a job.
+
method://hostname:port/printers/name
+
Specifies a printer.
+
+

So a typical printer URI would be +"ipp://foo.bar.com/printers/LaserJet".

+

In addition, the CUPS server also supports normal browser access to +"method://hostname:port/admin/", "method://hostname:port/classes/", +"method://hostname:port/jobs/", and "method://hostname:port/printers/" +to view and manage resources on the server dynamically.

+

3.2 CUPS IPP Operations

+

CUPS provides 13 extension operations in addition to most of the +standard IPP and registered extension operations: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operation NameCUPS +CodeBrief Description
Print-Job1.0 +0x0002Print a file.
Validate-Job1.0 +0x0004Validate job attributes.
Create-Job1.1 +0x0005Create a print job.
Send-Document1.1 +0x0006Send a file for a print job.
Cancel-Job1.0 +0x0008Cancel a print job.
Get-Job-Attributes1.0 +0x0009Get job attributes.
Get-Jobs1.0 +0x000AGet all jobs.
Get-Printer-Attributes1.00x000BGet printer attributes.
Hold-Job1.1 +0x000CHold a job for printing.
Release-Job1.1 +0x000DRelease a job for printing.
Pause-Printer1.0 +0x0010Pause printing on a printer.
Resume-Printer1.0 +0x0011Resume printing on a printer.
Purge-Jobs1.0 +0x0012Purge all jobs.
Set-Job-Attributes1.1 +0x0014Set attributes for a pending or held job.
CUPS-Get-Default1.0 +0x4001Get the default destination.
CUPS-Get-Printers1.0 +0x4002Get all of the available printers.
CUPS-Add-Printer1.0 +0x4003Add or modify a printer.
CUPS-Delete-Printer1.00x4004Delete a printer.
CUPS-Get-Classes1.0 +0x4005Get all of the available printer classes.
CUPS-Add-Class1.0 +0x4006Add or modify a printer class.
CUPS-Delete-Class1.0 +0x4007Delete a printer class.
CUPS-Accept-Jobs1.0 +0x4008Accept jobs on a printer or printer class.
CUPS-Reject-Jobs1.0 +0x4009Reject jobs on a printer or printer class.
CUPS-Set-Default1.0 +0x400ASet the default destination.
CUPS-Get-Devices1.1 +0x400BGet all of the available devices.
CUPS-Get-PPDs1.1 +0x400CGet all of the available PPDs.
CUPS-Move-Job1.1 +0x400DMove a job to a different printer.
+
+

+

4 Operations

+

The following sections describe the operations supported by CUPS. In +the interest of brevity, operations which use only the standard IPP +attributes are not described.

+

4.1 Print-Job Operation

+

The Print-Job operation (0x0002) prints a file.

+

4.1.1 Print-Job Request

+

The following groups of attributes are supplied as part of the +Print-Job request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Job Template Attributes

+
    +

    "job-billing" (text(MAX)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a billing string that is logged with +the page accounting information.

    +

    "job-sheets" (1setof type3 keyword | name(MAX)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies one or two banner pages that are +printed before and after any files in the print job. The name of +"none" is reserved to indicate that no banner page should be printed. +If the client does not specify this attribute then the value of the +"job-sheets-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value.

    +

    "media" (1setof type3 keyword | name(MAX)):

    +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output media. If +the client does not specify this attribute then the value of the +"media-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + media attribute value.

    +

    Other Job Template Attributes

    +
+

The Print-Job request is followed by a file to be printed.

+

4.1.2 Print-Job Response

+

The following groups of attributes are send as part of the Print-Job +Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Job Attributes

+
    +

    Standard Job Attributes

    +
+

4.2 Create-Job Operation

+

The Create-Job operation (0x0005) creates a new, empty print job.

+

4.2.1 Create-Job Request

+

The following groups of attributes are supplied as part of the +Create-Job request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Job Template Attributes

+
    +

    "job-billing" (text(MAX)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a billing string that is logged with +the page accounting information.

    +

    "job-sheets" (1setof type3 keyword | name(MAX)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies one or two banner pages that are +printed before and after any files in the print job. The name of +"none" is reserved to indicate that no banner page should be printed. +If the client does not specify this attribute then the value of the +"job-sheets-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value.

    +

    "media" (1setof type3 keyword | name(MAX)):

    +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output media. If +the client does not specify this attribute then the value of the +"media-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + media attribute value.

    +

    Standard Job Template Attributes

    +
+

4.2.2 Create-Job Response

+

The following groups of attributes are send as part of the +Create-Job Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Job Attributes

+
    +

    Standard Job Attributes

    +
+

4.3 Set-Job-Attributes Operation

+

The Set-Job-Attributes operation (0x0014) changes the attributes of +an active (not completed) job.

+

4.3.1 Set-Job-Attributes Request

+

The following groups of attributes are supplied as part of the +Set-Job-Attributes request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri) and "job-id" (integer)

    +

    OR

    +

    "job-uri":

    +

    The client MUST supply a URI for the specified printer and a job ID +number, or the job URI.

    +
+

Group 2: Job Template Attributes

+
    +

    "job-sheets" (1setof type3 keyword | name(MAX)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies one or two banner pages that are +printed before and after any files in the print job. The name of +"none" is reserved to indicate that no banner page should be printed. +If the client does not specify this attribute then the value of the +"job-sheets-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value.

    +

    "media" (1setof type3 keyword | name(MAX)):

    +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output media. If +the client does not specify this attribute then the value of the +"media-default" printer object attribute is used.

    +

    Note: Standard IPP only allows specification of a single + media attribute value.

    +

    Other Job Template Attributes

    +
+

4.3.2 Set-Job-Attributes Response

+

The following groups of attributes are send as part of the +Set-Job-Attributes Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.4 CUPS-Get-Default Operation

+

The CUPS-Get-Default operation (0x4001) returns the default printer +URI and attributes.

+

4.4.1 CUPS-Get-Default Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Default request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.4.2 CUPS-Get-Default Response

+

The following groups of attributes are send as part of the +CUPS-Get-Default Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Object Attributes

+
    +

    The set of requested attributes and their current values.

    +
+

4.5 CUPS-Get-Printers Operation

+

The CUPS-Get-Printers operation (0x4002) returns the printer +attributes for every printer known to the system. This may include +printers that are not served directly by the server.

+

4.5.1 CUPS-Get-Printers Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Printers request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number +of printers that are returned.

    +

    "printer-info" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printers are returned.

    +

    "printer-location" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printers are returned.

    +

    "printer-type" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type enumeration to select +which printers are returned.

    +

    "printer-type-mask" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type mask enumeration to +select which bits are used in the "printer-type" attribute.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.5.2 CUPS-Get-Printers Response

+

The following groups of attributes are send as part of the +CUPS-Get-Printers Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Object Attributes

+
    +

    The set of requested attributes and their current values for each +printer.

    +
+

4.6 CUPS-Add-Printer Operation

+

The CUPS-Add-Printer operation (0x4003) adds a new printer or +modifies an existing printer on the system.

+

4.6.1 CUPS-Add-Printer Request

+

The following groups of attributes are supplied as part of the +CUPS-Add-Printer request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Printer Object Attributes

+
    +

    "banner-end-default" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page name that is printed +after files in a job. The reserved name "none" is used to specify that +no banner page should be printed.

    +

    "banner-start-default" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page name that is printed +before files in a job. The reserved name "none" is used to specify +that no banner page should be printed.

    +

    "device-uri" (uri):

    +

    The client OPTIONALLY supplies a device URI for the specified +printer.

    +

    "ppd-name" (name(127)):

    +

    The client OPTIONALLY supplies a PPD name for the specified + printer.

    +

    "printer-is-accepting-jobs" (boolean):

    +

    The client OPTIONALLY supplies this boolean attribute indicating +whether or not the printer object should accept new jobs.

    +

    "printer-info" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating the + printer information string.

    +

    "printer-location" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +location of the printer.

    +

    "printer-more-info" (uri):

    +

    The client OPTIONALLY supplies this attribute indicating a URI for +additional printer information.

    +

    "printer-state" (type2 enum):

    +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized.

    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current printer state.

    +

    "requesting-user-name-allowed" (1setof name(127) | delete)

    +

    OR

    +

    "requesting-user-name-denied" (1setof name(127) | delete):

    +

    The client OPTIONALLY supplies one of these attributes to specify +an access control list for incoming print jobs. To allow all users +access to a printer, use the delete tag for the attribute value.

    +
+

The CUPS-Add-Printer request can optionally be followed by a PPD +file or System V interface script to be used for the printer. The +"ppd-name" attribute overrides any file that is attached to the end of +the request with a local CUPS PPD file.

+

4.6.2 CUPS-Add-Printer Response

+

The following groups of attributes are send as part of the +CUPS-Add-Printer Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.7 CUPS-Delete-Printer Operation

+

The CUPS-Delete-Printer operation (0x4004) removes an existing +printer from the system.

+

4.7.1 CUPS-Delete-Printer Request

+

The following groups of attributes are supplied as part of the +CUPS-Delete-Printer request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

4.7.2 CUPS-Delete-Printer Response

+

The following groups of attributes are send as part of the +CUPS-Delete-Printer Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.8 CUPS-Get-Classes Operation

+

The CUPS-Get-Classes operation (0x4005) returns the printer +attributes for every printer class known to the system. This may +include printer classes that are not served directly by the server.

+

4.8.1 CUPS-Get-Classes Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Classes request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number +of printer classes that are returned.

    +

    "printer-info" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printer classes are returned.

    +

    "printer-location" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printer classes are returned.

    +

    "printer-type" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type enumeration to select +which printer classes are returned.

    +

    "printer-type-mask" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type mask enumeration to +select which bits are used in the "printer-type" attribute.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.8.2 CUPS-Get-Classes Response

+

The following groups of attributes are send as part of the +CUPS-Get-Classes Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Class Object Attributes

+
    +

    The set of requested attributes and their current values for each +printer class.

    +
+

4.9 CUPS-Add-Class Operation

+

The CUPS-Add-Class operation (0x4006) adds a new printer class or +modifies and existing printer class on the system.

+

4.9.1 CUPS-Add-Class Request

+

The following groups of attributes are supplied as part of the +CUPS-Add-Class request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer class.

    +
+

Group 2: Printer Object Attributes

+
    +

    "member-uris" (1setof uri):

    +

    The client OPTIONALLY supplies the "member-uris" set specifying the +printers and printer classes that are part of the class.

    +

    "printer-is-accepting-jobs" (boolean):

    +

    The client OPTIONALLY supplies this boolean attribute indicating +whether or not the class object should accept new jobs.

    +

    "printer-info" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating the + printer information string.

    +

    "printer-location" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +location of the class.

    +

    "printer-more-info" (uri):

    +

    The client OPTIONALLY supplies this attribute indicating a URI for +additional class information.

    +

    "printer-state" (type2 enum):

    +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the class. Only the "idle" and "stopped" + enumerations are recognized.

    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current class state.

    +

    "requesting-user-name-allowed" (1setof name(127))

    +

    OR

    +

    "requesting-user-name-denied" (1setof name(127)):

    +

    The client OPTIONALLY supplies one of these attributes to specify +an access control list for incoming print jobs. To allow all users +access to a class, use the delete tag for the attribute value.

    +
+

4.9.2 CUPS-Add-Class Response

+

The following groups of attributes are send as part of the +CUPS-Add-Class Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.10 CUPS-Delete-Class Operation

+

The CUPS-Delete-Class operation (0x4007) removes an existing printer +class from the system.

+

4.10.1 CUPS-Delete-Class Request

+

The following groups of attributes are supplied as part of the +CUPS-Delete-Class request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer class.

    +
+

4.10.2 CUPS-Delete-Class Response

+

The following groups of attributes are send as part of the +CUPS-Delete-Class Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.11 CUPS-Accept-Jobs Operation

+

The CUPS-Accept-Jobs operation (0x4008) sets the +"printer-is-accepting-jobs" attribute to true for the specified printer +or printer class.

+

4.11.1 CUPS-Accept-Jobs Request

+

The following groups of attributes are supplied as part of the +CUPS-Accept-Jobs request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

4.11.2 CUPS-Accept-Jobs Response

+

The following groups of attributes are send as part of the +CUPS-Accept-Jobs Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.12 CUPS-Reject-Jobs Operation

+

The CUPS-Reject-Jobs operation (0x4009) sets +the"printer-is-accepting-jobs" attribute to false for the specified +printer or printer class.

+

4.12.1 CUPS-Reject-Jobs Request

+

The following groups of attributes are supplied as part of the +CUPS-Reject-Jobs request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

Group 2: Printer Object Attributes

+
    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current printer state.

    +
+

4.12.2 CUPS-Reject-Jobs Response

+

The following groups of attributes are send as part of the +CUPS-Reject-Jobs Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.13 CUPS-Set-Default Operation

+

The CUPS-Set-Default operation (0x400A) sets the default printer +destination for all clients when a resource name of "/printers" is +specified.

+

4.13.1 CUPS-Set-Default Request

+

The following groups of attributes are supplied as part of the +CUPS-Set-Default request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

4.13.2 CUPS-Set-Default Response

+

The following groups of attributes are send as part of the +CUPS-Set-Default Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.14 CUPS-Get-Devices Operation

+

The CUPS-Get-Devices operation (0x400B) returns all of the supported +device-uri's for the server (CUPS 1.1 and higher).

+

4.14.1 CUPS-Get-Devices Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Devices request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "device-class" (type1 keyword):

    +

    The client OPTIONALLY supplies a device class keyword to select + which devices are returned.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number of + devices that are returned.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'.

    +
+

4.14.2 CUPS-Get-Devices Response

+

The following groups of attributes are send as part of the +CUPS-Get-Devices Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Device Object Attributes

+
    +

    The set of requested attributes and their current values for each +device.

    +
+

4.15 CUPS-Get-PPDs Operation

+

The CUPS-Get-PPDs operation (0x400C) returns all of the locally +available PPD files on the system (CUPS 1.1 and higher).

+

4.15.1 CUPS-Get-PPDs Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-PPDs request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number of + PPDs that are returned.

    +

    "ppd-make" (text(127)):

    +

    The client OPTIONALLY supplies a printer manufacturer to select + which PPDs are returned.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'.

    +
+

4.15.2 CUPS-Get-PPDs Response

+

The following groups of attributes are send as part of the +CUPS-Get-PPDs Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: PPD Attributes

+
    +

    The set of requested attributes and their current values for each + PPD file.

    +
+

4.16 CUPS-Move-Job Operation

+

The CUPS-Move-Job operation (0x400D) moves an active print job to a +different printer (CUPS 1.1 and higher).

+

4.16.1 CUPS-Move-Job Request

+

The following groups of attributes are supplied as part of the +CUPS-Move-Job request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri) and "job-id" (integer)

    +

    OR

    +

    "job-uri":

    +

    The client MUST supply a URI for the specified printer and a job ID +number, or the job URI.

    +
+

Group 2: Job Template Attributes

+
    +

    "job-printer-uri" (uri)

    +

    The client MUST supply a URI for a printer on the same server.

    +
+

4.16.2 CUPS-Move-Job Response

+

The following groups of attributes are send as part of the +CUPS-Move-Job Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

5 Attributes

+

CUPS provides many extension attributes to support multiple devices, +PPD files, standard job filters, printers, and printer classes.

+

5.1 Device Attributes

+

Device attributes are returned by the CUPS-Get-Devices operation and +enumerate all of the available hardware devices and network protocols +that are supported by the server.

+

5.1.1 device-class (type2 keyword)

+

The device-class attribute specifies the class of device and can be +one of the following:

+
    +
  • "file" - a disk file.
  • +
  • "direct" - a parallel or fixed-rate serial data port, currently +used for Centronics, IEEE-1284, and USB printer ports.
  • +
  • "serial" - a variable-rate serial port.
  • +
  • "network" - a network connection, typically via AppSocket, HTTP, +IPP, LPD, or SMB/CIFS protocols.
  • +
+

5.1.2 device-info (text(127))

+

The device-info attribute specifies a human-readable string +describing the device, e.g. "Parallel Port #1".

+

5.1.3 device-make-and-model (text(127))

+

The device-makr-and-model attribute specifies a device +identification string provided by the printer connected to the device. +If the device or printer does not support identification then this +attribute contains the string "unknown".

+

5.1.4 device-uri (uri)

+

The device-uri attribute specifies a unique identifier for the +device. The actual format of the device-uri string depends on the value +of the device-class attribute:

+
    +
  • "file" - The device-uri will be of the form + "file:/path/to/filename".
  • +
  • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" in +the current implementation.
  • +
  • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". The baud +value is the data rate in bits per second; the supported values depend +on the underlying hardware. The parity value can be one of "none", +"even", or "odd". The flow value can be one of "none", "soft" +(XON/XOFF handshaking), "hard" or "rts/cts" (RTS/CTS handshaking), or +"dtrdsr" (DTR/DSR handshaking).
  • +

    The URI returned by CUPS-Get-Devices will contain the maximum baud +rate supported by the device and the best type of flow control +available ("soft" or "hard").

    +
  • "network" - The device-uri will be of the form + "method://[username:password@]hostname[:port]/[resource]", where +method may be "http", "ipp", "lpd", "smb", or "socket" in the current +implementation.
  • +

    The URI returned by CUPS-Get-Devices will only contain the method +name followed by two slashes ("method://"). It is up to the client +application to add the appropriate host and other information when +adding a new printer.

    +

    The URI returned by Get-Printer-Attributes and CUPS-Get-Printers +has any username and password information stripped; the information is +still stored and used by the server internally to perform any needed +authentication.

    +
+

5.2 Job Template Attributes

+

5.2.1 blackplot (boolean)

+

The blackplot attribute specifies whether HP-GL/2 plot files should +be rendered entirely in black ink (blackplot=true) or using the colors +and shades specified in the file (blackplot=false). The default value +is false.

+

5.2.2 brightness (integer(0:200))

+

The brightness attribute specifies the overall brightness of the +printed output in percent. A brightness of 100 is normal, while 200 is +twice as bright and 50 is half as bright. The default value is 100.

+

Brightness is applied to the Cyan, Magenta, Yellow, and Black values +using the function "f(x) = brightness / 100 * x".

+

5.2.3 columns (integer(1:4))

+

The columns attribute specifies the number of columns to generate +when printing text files. The default value is 1.

+

5.2.4 cpi (type2 enum)

+

The cpi attribute specifies the number of characters per inch when +printing text files. Only the values 10, 12, and 17 are currently +supported. The default value is 10.

+

5.2.5 fitplot (boolean)

+

The fitplot attribute specifies whether to scale HP-GL/2 plot files +to fit on the selected media (fitplot=true) or use the physical scale +specified in the plot file (fitplot=false). The default value is false.

+

5.2.6 gamma (integer(1:10000))

+

The gamma attribute specifies the luminance correction for the +output. A value of 1000 specifies no correction, while values of 2000 +and 500 will generate lighter and darker output, respectively. The +default value is 1000.

+

Gamma is applied to the Red, Green, and Blue values (or luminance +for grayscale output) using the function "f(x) = x(1000/gamma) +".

+

5.2.7 hue (integer(-180:180))

+

The hue attribute specifies a color hue rotation when printing image +files. The default value is 0.

+

5.2.8 job-billing (text(MAX))

+

(CUPS 1.1 and higher)

+

The job-billing attribute provides a text value to associate with a +job for billing purposes.

+

5.2.9 job-hold-until (keyword | name(MAX))

+

(CUPS 1.1 and higher)

+

The job-hold-until attribute specifies a hold time. In addition to +the standard IPP/1.1 keyword names, CUPS supports name values of the +form "HH:MM" and "HH:MM:SS" that specify a hold time. The hold time is +in Greenwich Mean Time (GMT) and not in the local time zone. If +the specified time is less than the current time, the job is held until +the next day.

+

5.2.10 job-sheets (1setof type3 keyword | +name(MAX))

+

(CUPS 1.1 and higher)

+

The job-sheets attribute specifies one or two banner files that are +printed before and after a job. The reserved value of "none" disables +banner printing. The default value is stored in the job-sheets-default +attribute.

+

If only one value is supplied, the banner file is printed before the +job. If two values are supplied, the first value is used as the +starting banner file and the second as the ending banner file.

+

5.2.11 job-originating-host-name (name(MAX))

+

(CUPS 1.1.5 and higher)

+

The job-originating-host-name attribute specifies the host from +which the job was queued. The value will be the hostname or IP address +of the client depending on whether hostname resolution is enabled. The +localhost address (127.0.0.1) is always resolved to the name +"localhost".

+

This attribute is read-only.

+

5.2.12 lpi (type2 enum)

+

The lpi attribute specifies the number of lines per inch when +printing text files. Only the values 6 and 8 are currently supported. +The default value is 6.

+

5.2.13 page-bottom (integer(0:MAX))

+

The page-bottom attribute specifies the bottom margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.14 page-label (text(MAX))

+

(CUPS 1.1.7 and higher)

+

The page-label attribute provides a text value to place in the +header and footer on each page. If a classification level is set on the +server, then this classification is printed before the page label.

+

5.2.15 page-left (integer(0:MAX))

+

The page-left attribute specifies the left margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.16 page-right (integer(0:MAX))

+

The page-right attribute specifies the right margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.17 page-set (type2 keyword)

+

The page-set attribute specifies which pages to print in a file. The +supported keywords are "all", "even", and "odd". The default value is +"all".

+

5.2.18 page-top (integer(0:MAX))

+

The page-top attribute specifies the top margin in points (72 points +equals 1 inch). The default value is the device physical margin.

+

5.2.19 penwidth (integer(0:MAX))

+

The penwidth attribute specifies the default pen width in +micrometers when printing HP-GL/2 plot files. The default value is 1000 +(1 millimeter).

+

5.2.20 position (type2 keyword)

+

The position attribute specifies the location of image files on the +media. The following keyword values are recognized:

+
    +
  • center - Center the image on the page (default)
  • +
  • top - Print the image centered at the top of the page
  • +
  • left - Print the image centered on the left of page
  • +
  • right - Print the image centered on the right of the +page
  • +
  • top-left - Print the image at the top left corner of + the page
  • +
  • top-right - Print the image at the top right corner of + the page
  • +
  • bottom - Print the image centered at the bottom of + the page
  • +
  • bottom-left - Print the image at the bottom left + corner of the page
  • +
  • bottom-right - Print the image at the bottom right + corner of the page
  • +
+

5.2.21 ppi (integer(1:MAX))

+

The ppi attribute specifies the resolution of an image file in +pixels per inch. The default value is the resolution included with the +file or 128 if no resolution information is available.

+

5.2.22 prettyprint (boolean)

+

The prettyprint attribute specifies whether text files should be +printed with a shaded header and keyword highlighting +(prettyprint=true) or without additional formatting +(prettyprint=false). The default value is false.

+

5.2.23 saturation (integer(0:200))

+

The saturation attribute specifies the color saturation when +printing image files. A saturation of 100 is normal, while values of 50 +and 200 will be half and twice as colorful, respectively. The default +value is 100.

+

5.2.24 scaling (integer(1:1000))

+

The scaling attribute specifies the scaling of image files with +respect to the selected media. A value of 100 specifies that the image +file should fit 100% of the page, or as much as possible given the +image dimensions. The default value is unspecified.

+

The scaling attribute overrides the ppi attribute if specified.

+

5.2.25 wrap (boolean)

+

The wrap attribute specifies whether long lines should be wrapped +(wrap=true) or not (wrap=false) when printing text files. The default +value is true.

+

5.3 PPD Attributes

+

5.3.1 ppd-natural-language (naturalLanguage)

+

The ppd-natural-language attribute specifies the language encoding +of the PPD file (the LanguageVersion attribute in the PPD file). If the +language is unknown or undefined then "en" (English) is assumed.

+

5.3.2 ppd-make (text(127))

+

The ppd-make attribute specifies the manufacturer of the printer +(the Manufacturer attribute in the PPD file). If the manufacturer is +not specified in the PPD file then an educated guess is made using the +NickName attribute in the PPD file.

+

5.3.3 ppd-make-and-model (text(127))

+

The ppd-make-and-model attribute specifies the manufacturer and +model name of the PPD file (the NickName attribute in the PPD file). If +the make and model is not specified in the PPD file then the ModelName +or ShortNickName attributes are used instead.

+

5.3.4 ppd-name (name(255))

+

The ppd-name attribute specifies the PPD filename on the server +relative to the model directory. The forward slash (/) is used to +delineate directories.

+

5.4 Printer Attributes

+

5.4.1 job-k-limit (integer)

+

(CUPS 1.1 and higher)

+

The job-k-limit attribute specifies the maximum number of kilobytes +that may be printed by a user, including banner files. The default +value of 0 specifies that there is no limit.

+

5.4.2 job-page-limit (integer)

+

(CUPS 1.1 and higher)

+

The job-page-limit attribute specifies the maximum number of pages +that may be printed by a user, including banner files. The default +value of 0 specifies that there is no limit.

+

5.4.3 job-quota-period (integer)

+

(CUPS 1.1 and higher)

+

The job-quota-period attribute specifies the time period used for +quota calculations, in seconds. The default value of 0 specifies that +the limits apply to all jobs that have been printed by a user that are +still known to the system.

+

5.4.4 job-sheets-supported (1setof type3 keyword | +name(MAX))

+

(CUPS 1.1 and higher)

+

The job-sheets-supported attribute specifies the available banner +files. There will always be at least one banner file available called +"none".

+

5.4.5 printer-type (type2 enum)

+

The printer-type attribute specifies printer type and capability +bits for the printer or class. The default value is computed from +internal state information and the PPD file for the printer. The +following bits are defined: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
0x00000001Is a printer class.
0x00000002Is a remote +destination.
0x00000004Can print in black.
0x00000008Can print in color.
0x00000010Can print on both +sides of the page in hardware.
0x00000020Can staple output.
0x00000040Can do fast copies +in hardware.
0x00000080Can do fast copy +collation in hardware.
0x00000100Can punch output.
0x00000200Can cover output.
0x00000400Can bind output.
0x00000800Can sort output.
0x00001000Can handle media +up to US-Legal/A4.
0x00002000Can handle media +from US-Legal/A4 to ISO-C/A2.
0x00004000Can handle media +larger than ISO-C/A2.
0x00008000Can handle +user-defined media sizes.
0x00010000Is an implicit +(server-generated) class.
+
+

+

5.4.6 printer-type-mask (type2 enum)

+

(CUPS 1.1 and higher)

+

The printer-type-mask attribute is used to choose printers or +classes with the CUPS-Get-Printers and CUPS-Get-Classes operations. The +bits are defined identically to the printer-type attribute and default +to all 1's.

+

5.4.7 requesting-user-name-allowed (1setof +name(127))

+

(CUPS 1.1 and higher)

+

The requesting-user-name-allowed attribute lists all of the users +that are allowed to access a printer or class. Either this attribute or +the requesting-user-name-denied attribute will be defined, but not +both.

+

5.4.8 requesting-user-name-denied (1setof name(127)) +

+

(CUPS 1.1 and higher)

+

The requesting-user-name-denied attribute lists all of the users +that are not allowed to access a printer or class. Either this +attribute or the requesting-user-name-allowed attribute will be +defined, but not both.

+

5.5 Printer Class Attributes

+

5.5.1 member-names (1setof name(127))

+

The member-names attribute specifies each of the printer-name +attributes of the member printers and classes. Each name corresponds to +the same element of the member-uris attribute.

+

5.5.2 member-uris (1setof uri)

+

The member-uris attribute specifies each of the printer-uri +attributes of the member printers and classes. Each URI corresponds to +the same element of the member-names attribute.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/ipp.pdf b/doc/ipp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4036884ec97dd1a5f37b14c61561eaebb59657d4 GIT binary patch literal 103091 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 + + + + + CUPS Implementation of IPP + + + +

Scope

+ +

Identification

+ +

This document provides an overview of the Internet Printing Protocol +("IPP") version 1.1 as implemented in the Common UNIX Printing System +("CUPS") version 1.1. + + + +

Document Overview

+ +

This document is organized into the following sections: + +

+ + + +

Overview

+ +

CUPS 1.1 implements IPP/1.1 and the operations and attributes +defined in the "IPP: Job and Printer Set Operations", +"IPP/1.1: Output-bin Attribute Extension", and "IPP/1.1: finishings +'fold',' trim', and 'bale' attribute values extension" specifications. + +

CUPS also provides 13 new operations and many new attributes to +support multiple IPP printers and printer classes on a single host. + +

IPP URIs

+ +

CUPS supports both the "http" and "ipp" methods. The following +resource names are used: + +

+ +
method://hostname:port/ + +
Can be used for all "get" operations. + +
method://hostname:port/admin + +
Used for all administrative operations. + +
method://hostname:port/classes/name + +
Specifies a printer class. + +
method://hostname:port/jobs/id + +
Specifies a job. + +
method://hostname:port/printers/name + +
Specifies a printer. + +
+ +

So a typical printer URI would be "ipp://foo.bar.com/printers/LaserJet". + +

In addition, the CUPS server also supports normal browser access to +"method://hostname:port/admin/", "method://hostname:port/classes/", +"method://hostname:port/jobs/", and "method://hostname:port/printers/" +to view and manage resources on the server dynamically. + +

CUPS IPP Operations

+ +

CUPS provides 13 extension operations in addition to most of the +standard IPP and registered extension operations: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operation NameCUPSCodeBrief Description
Print-Job1.00x0002Print a file.
Validate-Job1.00x0004Validate job attributes.
Create-Job1.10x0005Create a print job.
Send-Document1.10x0006Send a file for a print job.
Cancel-Job1.00x0008Cancel a print job.
Get-Job-Attributes1.00x0009Get job attributes.
Get-Jobs1.00x000AGet all jobs.
Get-Printer-Attributes1.00x000BGet printer attributes.
Hold-Job1.10x000CHold a job for printing.
Release-Job1.10x000DRelease a job for printing.
Pause-Printer1.00x0010Pause printing on a printer.
Resume-Printer1.00x0011Resume printing on a printer.
Purge-Jobs1.00x0012Purge all jobs.
Set-Job-Attributes1.10x0014Set attributes for a pending or held job.
CUPS-Get-Default1.00x4001Get the default destination.
CUPS-Get-Printers1.00x4002Get all of the available printers.
CUPS-Add-Printer1.00x4003Add or modify a printer.
CUPS-Delete-Printer1.00x4004Delete a printer.
CUPS-Get-Classes1.00x4005Get all of the available printer classes.
CUPS-Add-Class1.00x4006Add or modify a printer class.
CUPS-Delete-Class1.00x4007Delete a printer class.
CUPS-Accept-Jobs1.00x4008Accept jobs on a printer or printer class.
CUPS-Reject-Jobs1.00x4009Reject jobs on a printer or printer class.
CUPS-Set-Default1.00x400ASet the default destination.
CUPS-Get-Devices1.10x400BGet all of the available devices.
CUPS-Get-PPDs1.10x400CGet all of the available PPDs.
CUPS-Move-Job1.10x400DMove a job to a different printer.
+
+ +

Operations

+ +

The following sections describe the operations supported by CUPS. +In the interest of brevity, operations which use only the standard +IPP attributes are not described. + +

Print-Job Operation

+ +

The Print-Job operation (0x0002) prints a file. + +

Print-Job Request

+ +

The following groups of attributes are supplied as part of the +Print-Job request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "job-billing" (text(MAX)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a billing string that is logged + with the page accounting information. + +

    "job-sheets" (1setof type3 keyword | name(MAX)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies one or two banner pages that + are printed before and after any files in the print job. The + name of "none" is reserved to indicate that no banner page + should be printed. If the client does not specify this + attribute then the value of the "job-sheets-default" printer + object attribute is used. + +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

    "media" (1setof type3 keyword | name(MAX)): + +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output + media. If the client does not specify this attribute then the + value of the "media-default" printer object attribute is used. + +

    Note: Standard IPP only allows specification of a single + media attribute value. + +

    Other Job Template Attributes + +

+ +

The Print-Job request is followed by a file to be printed. + +

Print-Job Response

+ +

The following groups of attributes are send as part of the Print-Job +Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Job Attributes + +

    + +

    Standard Job Attributes + +

+ +

Create-Job Operation

+ +

The Create-Job operation (0x0005) creates a new, empty print job. + +

Create-Job Request

+ +

The following groups of attributes are supplied as part of the +Create-Job request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "job-billing" (text(MAX)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a billing string that is logged + with the page accounting information. + +

    "job-sheets" (1setof type3 keyword | name(MAX)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies one or two banner pages that + are printed before and after any files in the print job. The + name of "none" is reserved to indicate that no banner page + should be printed. If the client does not specify this + attribute then the value of the "job-sheets-default" printer + object attribute is used. + +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

    "media" (1setof type3 keyword | name(MAX)): + +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output + media. If the client does not specify this attribute then the + value of the "media-default" printer object attribute is used. + +

    Note: Standard IPP only allows specification of a single + media attribute value. + +

    Standard Job Template Attributes + +

+ +

Create-Job Response

+ +

The following groups of attributes are send as part of the +Create-Job Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Job Attributes + +

    + +

    Standard Job Attributes + +

+ +

Set-Job-Attributes Operation

+ +

The Set-Job-Attributes operation (0x0014) changes the attributes of +an active (not completed) job. + +

Set-Job-Attributes Request

+ +

The following groups of attributes are supplied as part of the +Set-Job-Attributes request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri) and "job-id" (integer) +

    OR +

    "job-uri": + +

    The client MUST supply a URI for the specified printer and + a job ID number, or the job URI. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "job-sheets" (1setof type3 keyword | name(MAX)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies one or two banner pages that + are printed before and after any files in the print job. The + name of "none" is reserved to indicate that no banner page + should be printed. If the client does not specify this + attribute then the value of the "job-sheets-default" printer + object attribute is used. + +

    Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

    "media" (1setof type3 keyword | name(MAX)): + +

    The client OPTIONALLY supplies one or more media attributes + specifying the size, type, source, and color of the output + media. If the client does not specify this attribute then the + value of the "media-default" printer object attribute is used. + +

    Note: Standard IPP only allows specification of a single + media attribute value. + +

    Other Job Template Attributes + +

+ +

Set-Job-Attributes Response

+ +

The following groups of attributes are send as part of the Set-Job-Attributes +Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Default Operation

+ +

The CUPS-Get-Default operation (0x4001) returns the default printer +URI and attributes. + +

CUPS-Get-Default Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Default request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server + responds as if this attribute had been supplied with a value of + 'all'. + +

+ +

CUPS-Get-Default Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Default Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    The set of requested attributes and their current values. + +

+ +

CUPS-Get-Printers Operation

+ +

The CUPS-Get-Printers operation (0x4002) returns the printer +attributes for every printer known to the system. This may include +printers that are not served directly by the server. + +

CUPS-Get-Printers Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Printers request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the + number of printers that are returned. + +

    "printer-info" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printers are returned. + +

    "printer-location" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printers are returned. + +

    "printer-type" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type enumeration to + select which printers are returned. + +

    "printer-type-mask" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type mask + enumeration to select which bits are used in the "printer-type" + attribute. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server + responds as if this attribute had been supplied with a value of + 'all'. + +

+ +

CUPS-Get-Printers Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Printers Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    The set of requested attributes and their current values for + each printer. + +

+ +

CUPS-Add-Printer Operation

+ +

The CUPS-Add-Printer operation (0x4003) adds a new printer or +modifies an existing printer on the system. + +

CUPS-Add-Printer Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Add-Printer request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "banner-end-default" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page name that is + printed after files in a job. The reserved name "none" is used to + specify that no banner page should be printed. + +

    "banner-start-default" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page name that is + printed before files in a job. The reserved name "none" is used to + specify that no banner page should be printed. + +

    "device-uri" (uri): + +

    The client OPTIONALLY supplies a device URI for the + specified printer. + +

    "ppd-name" (name(127)): + +

    The client OPTIONALLY supplies a PPD name for the specified + printer. + +

    "printer-is-accepting-jobs" (boolean): + +

    The client OPTIONALLY supplies this boolean attribute + indicating whether or not the printer object should accept new jobs. + +

    "printer-info" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating the + printer information string. + +

    "printer-location" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual location of the printer. + +

    "printer-more-info" (uri): + +

    The client OPTIONALLY supplies this attribute indicating a + URI for additional printer information. + +

    "printer-state" (type2 enum): + +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized. + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current printer state. + +

    "requesting-user-name-allowed" (1setof name(127) | delete) +

    OR +

    "requesting-user-name-denied" (1setof name(127) | delete): + +

    The client OPTIONALLY supplies one of these attributes to + specify an access control list for incoming print jobs. To allow + all users access to a printer, use the delete tag for the + attribute value. + +

+ +

The CUPS-Add-Printer request can optionally be followed by a PPD +file or System V interface script to be used for the printer. The +"ppd-name" attribute overrides any file that is attached to the end of +the request with a local CUPS PPD file. + +

CUPS-Add-Printer Response

+ +

The following groups of attributes are send as part of the +CUPS-Add-Printer Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Delete-Printer Operation

+ +

The CUPS-Delete-Printer operation (0x4004) removes an existing +printer from the system. + +

CUPS-Delete-Printer Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Delete-Printer request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

CUPS-Delete-Printer Response

+ +

The following groups of attributes are send as part of the +CUPS-Delete-Printer Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Classes Operation

+ +

The CUPS-Get-Classes operation (0x4005) returns the printer +attributes for every printer class known to the system. This may +include printer classes that are not served directly by the server. + +

CUPS-Get-Classes Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Classes request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the + number of printer classes that are returned. + +

    "printer-info" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printer classes are returned. + +

    "printer-location" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printer classes are returned. + +

    "printer-type" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type enumeration to + select which printer classes are returned. + +

    "printer-type-mask" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type mask + enumeration to select which bits are used in the "printer-type" + attribute. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server responds as + if this attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-Classes Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Classes Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Class Object Attributes + +

    + +

    The set of requested attributes and their current values for + each printer class. + +

+ +

CUPS-Add-Class Operation

+ +

The CUPS-Add-Class operation (0x4006) adds a new printer class or +modifies and existing printer class on the system. + +

CUPS-Add-Class Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Add-Class request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer class. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "member-uris" (1setof uri): + +

    The client OPTIONALLY supplies the "member-uris" set + specifying the printers and printer classes that are part of the class. + +

    "printer-is-accepting-jobs" (boolean): + +

    The client OPTIONALLY supplies this boolean attribute + indicating whether or not the class object should accept new jobs. + +

    "printer-info" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating the + printer information string. + +

    "printer-location" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual location of the class. + +

    "printer-more-info" (uri): + +

    The client OPTIONALLY supplies this attribute indicating a + URI for additional class information. + +

    "printer-state" (type2 enum): + +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the class. Only the "idle" and "stopped" + enumerations are recognized. + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current class state. + +

    "requesting-user-name-allowed" (1setof name(127)) +

    OR +

    "requesting-user-name-denied" (1setof name(127)): + +

    The client OPTIONALLY supplies one of these attributes to + specify an access control list for incoming print jobs. To allow + all users access to a class, use the delete tag for the + attribute value. + +

+ +

CUPS-Add-Class Response

+ +

The following groups of attributes are send as part of the CUPS-Add-Class Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Delete-Class Operation

+ +

The CUPS-Delete-Class operation (0x4007) removes an existing printer +class from the system. + +

CUPS-Delete-Class Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Delete-Class request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer class. + +

+ +

CUPS-Delete-Class Response

+ +

The following groups of attributes are send as part of the +CUPS-Delete-Class Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Accept-Jobs Operation

+ +

The CUPS-Accept-Jobs operation (0x4008) sets the +"printer-is-accepting-jobs" attribute to true for the specified printer +or printer class. + +

CUPS-Accept-Jobs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Accept-Jobs request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or printer class. + +

+ +

CUPS-Accept-Jobs Response

+ +

The following groups of attributes are send as part of the +CUPS-Accept-Jobs Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Reject-Jobs Operation

+ +

The CUPS-Reject-Jobs operation (0x4009) sets +the"printer-is-accepting-jobs" attribute to false for the specified +printer or printer class. + +

CUPS-Reject-Jobs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Reject-Jobs request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or printer class. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current printer state. + +

+ +

CUPS-Reject-Jobs Response

+ +

The following groups of attributes are send as part of the +CUPS-Reject-Jobs Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Set-Default Operation

+ +

The CUPS-Set-Default operation (0x400A) sets the default printer +destination for all clients when a resource name of "/printers" is +specified. + +

CUPS-Set-Default Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Set-Default request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or + printer class. + +

+ +

CUPS-Set-Default Response

+ +

The following groups of attributes are send as part of the +CUPS-Set-Default Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Devices Operation

+ +

The CUPS-Get-Devices operation (0x400B) returns all of the supported +device-uri's for the server (CUPS 1.1 and higher). + +

CUPS-Get-Devices Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Devices request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "device-class" (type1 keyword): + +

    The client OPTIONALLY supplies a device class keyword to select + which devices are returned. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the number of + devices that are returned. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-Devices Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Devices Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Device Object Attributes + +

    + +

    The set of requested attributes and their current values for + each device. + +

+ +

CUPS-Get-PPDs Operation

+ +

The CUPS-Get-PPDs operation (0x400C) returns all of the locally +available PPD files on the system (CUPS 1.1 and higher). + +

CUPS-Get-PPDs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-PPDs request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the number of + PPDs that are returned. + +

    "ppd-make" (text(127)): + +

    The client OPTIONALLY supplies a printer manufacturer to select + which PPDs are returned. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-PPDs Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-PPDs Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: PPD Attributes + +

    + +

    The set of requested attributes and their current values for each + PPD file. + +

+ +

CUPS-Move-Job Operation

+ +

The CUPS-Move-Job operation (0x400D) moves an active print job to a +different printer (CUPS 1.1 and higher). + +

CUPS-Move-Job Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Move-Job request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri) and "job-id" (integer) +

    OR +

    "job-uri": + +

    The client MUST supply a URI for the specified printer and + a job ID number, or the job URI. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "job-printer-uri" (uri) + +

    The client MUST supply a URI for a printer on the same server. + +

+ +

CUPS-Move-Job Response

+ +

The following groups of attributes are send as part of the +CUPS-Move-Job Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Attributes

+ +

CUPS provides many extension attributes to support multiple devices, +PPD files, standard job filters, printers, and printer classes. + +

Device Attributes

+ +

Device attributes are returned by the CUPS-Get-Devices operation and +enumerate all of the available hardware devices and network protocols +that are supported by the server. + +

device-class (type2 keyword)

+ +

The device-class attribute specifies the class of device and can be +one of the following: + +

    + +
  • "file" - a disk file. + +
  • "direct" - a parallel or fixed-rate serial data port, + currently used for Centronics, IEEE-1284, and USB printer + ports. + +
  • "serial" - a variable-rate serial port. + +
  • "network" - a network connection, typically via AppSocket, + HTTP, IPP, LPD, or SMB/CIFS protocols. + +
+ +

device-info (text(127))

+ +

The device-info attribute specifies a human-readable string describing +the device, e.g. "Parallel Port #1". + +

device-make-and-model (text(127))

+ +

The device-makr-and-model attribute specifies a device +identification string provided by the printer connected to the device. +If the device or printer does not support identification then this +attribute contains the string "unknown". + +

device-uri (uri)

+ +

The device-uri attribute specifies a unique identifier for the +device. The actual format of the device-uri string depends on the value +of the device-class attribute: + +

    + +
  • "file" - The device-uri will be of the form + "file:/path/to/filename". + +
  • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" + in the current implementation. + +
  • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". + The baud value is the data rate in bits per second; the + supported values depend on the underlying hardware. + The parity value can be one of "none", "even", or "odd". + The flow value can be one of "none", "soft" (XON/XOFF + handshaking), "hard" or "rts/cts" (RTS/CTS handshaking), + or "dtrdsr" (DTR/DSR handshaking). + +

    The URI returned by CUPS-Get-Devices will contain the + maximum baud rate supported by the device and the best + type of flow control available ("soft" or "hard"). + +

  • "network" - The device-uri will be of the form + "method://[username:password@]hostname[:port]/[resource]", + where method may be "http", "ipp", "lpd", "smb", or + "socket" in the current implementation. + +

    The URI returned by CUPS-Get-Devices will only contain + the method name followed by two slashes ("method://"). + It is up to the client application to add the appropriate + host and other information when adding a new printer. + +

    The URI returned by Get-Printer-Attributes and + CUPS-Get-Printers has any username and password information + stripped; the information is still stored and used by the + server internally to perform any needed authentication. + +

+ +

Job Template Attributes

+ +

blackplot (boolean)

+ +

The blackplot attribute specifies whether HP-GL/2 plot files should be +rendered entirely in black ink (blackplot=true) or using the colors and shades +specified in the file (blackplot=false). The default value is false. + +

brightness (integer(0:200))

+ +

The brightness attribute specifies the overall brightness of the printed +output in percent. A brightness of 100 is normal, while 200 is twice as +bright and 50 is half as bright. The default value is 100. + +

Brightness is applied to the Cyan, Magenta, Yellow, and Black values using +the function "f(x) = brightness / 100 * x". + +

columns (integer(1:4))

+ +

The columns attribute specifies the number of columns to generate when +printing text files. The default value is 1. + +

cpi (type2 enum)

+ +

The cpi attribute specifies the number of characters per inch when +printing text files. Only the values 10, 12, and 17 are currently +supported. The default value is 10. + +

fitplot (boolean)

+ +

The fitplot attribute specifies whether to scale HP-GL/2 plot files to +fit on the selected media (fitplot=true) or use the physical scale specified +in the plot file (fitplot=false). The default value is false. + +

gamma (integer(1:10000))

+ +

The gamma attribute specifies the luminance correction for the output. +A value of 1000 specifies no correction, while values of 2000 and 500 will +generate lighter and darker output, respectively. The default value is +1000. + +

Gamma is applied to the Red, Green, and Blue values (or luminance for +grayscale output) using the function "f(x) = x(1000/gamma)". + +

hue (integer(-180:180))

+ +

The hue attribute specifies a color hue rotation when printing image +files. The default value is 0. + +

job-billing (text(MAX))

+ +

(CUPS 1.1 and higher) + +

The job-billing attribute provides a text value to associate with a job +for billing purposes. + +

job-hold-until (keyword | name(MAX))

+ +

(CUPS 1.1 and higher) + +

The job-hold-until attribute specifies a hold time. In addition to the +standard IPP/1.1 keyword names, CUPS supports name values of the form +"HH:MM" and "HH:MM:SS" that specify a hold time. The hold time is in +Greenwich Mean Time (GMT) and not in the local time zone. If the +specified time is less than the current time, the job is held until the +next day. + +

job-sheets (1setof type3 keyword | name(MAX))

+ +

(CUPS 1.1 and higher) + +

The job-sheets attribute specifies one or two banner files that are printed +before and after a job. The reserved value of "none" disables banner printing. +The default value is stored in the job-sheets-default attribute. + +

If only one value is supplied, the banner file is printed before the job. +If two values are supplied, the first value is used as the starting banner +file and the second as the ending banner file. + +

job-originating-host-name (name(MAX))

+ +

(CUPS 1.1.5 and higher) + +

The job-originating-host-name attribute specifies the host +from which the job was queued. The value will be the hostname or +IP address of the client depending on whether hostname +resolution is enabled. The localhost address (127.0.0.1) is +always resolved to the name "localhost". + +

This attribute is read-only. + +

lpi (type2 enum)

+ +

The lpi attribute specifies the number of lines per inch when +printing text files. Only the values 6 and 8 are currently supported. +The default value is 6. + +

page-bottom (integer(0:MAX))

+ +

The page-bottom attribute specifies the bottom margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-label (text(MAX))

+ +

(CUPS 1.1.7 and higher) + +

The page-label attribute provides a text value to place in +the header and footer on each page. If a classification level is +set on the server, then this classification is printed before +the page label. + +

page-left (integer(0:MAX))

+ +

The page-left attribute specifies the left margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-right (integer(0:MAX))

+ +

The page-right attribute specifies the right margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-set (type2 keyword)

+ +

The page-set attribute specifies which pages to print in a file. The +supported keywords are "all", "even", and "odd". The default value is +"all". + +

page-top (integer(0:MAX))

+ +

The page-top attribute specifies the top margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

penwidth (integer(0:MAX))

+ +

The penwidth attribute specifies the default pen width in micrometers +when printing HP-GL/2 plot files. The default value is 1000 (1 millimeter). + +

position (type2 keyword)

+ +

The position attribute specifies the location of image files on the +media. The following keyword values are recognized: + +

    + +
  • center - Center the image on the page (default) + +
  • top - Print the image centered at the top of the page + +
  • left - Print the image centered on the left of page + +
  • right - Print the image centered on the right of the page + +
  • top-left - Print the image at the top left corner of + the page + +
  • top-right - Print the image at the top right corner of + the page + +
  • bottom - Print the image centered at the bottom of + the page + +
  • bottom-left - Print the image at the bottom left + corner of the page + +
  • bottom-right - Print the image at the bottom right + corner of the page + +
+ +

ppi (integer(1:MAX))

+ +

The ppi attribute specifies the resolution of an image file in pixels +per inch. The default value is the resolution included with the file or +128 if no resolution information is available. + +

prettyprint (boolean)

+ +

The prettyprint attribute specifies whether text files should be printed +with a shaded header and keyword highlighting (prettyprint=true) or without +additional formatting (prettyprint=false). The default value is false. + +

saturation (integer(0:200))

+ +

The saturation attribute specifies the color saturation when +printing image files. A saturation of 100 is normal, while values of 50 +and 200 will be half and twice as colorful, respectively. The default +value is 100. + +

scaling (integer(1:1000))

+ +

The scaling attribute specifies the scaling of image files with +respect to the selected media. A value of 100 specifies that the image +file should fit 100% of the page, or as much as possible given the +image dimensions. The default value is unspecified. + +

The scaling attribute overrides the ppi attribute if specified. + +

wrap (boolean)

+ +

The wrap attribute specifies whether long lines should be wrapped +(wrap=true) or not (wrap=false) when printing text files. The default +value is true. + +

PPD Attributes

+ +

ppd-natural-language (naturalLanguage)

+ +

The ppd-natural-language attribute specifies the language encoding +of the PPD file (the LanguageVersion attribute in the PPD file). If the +language is unknown or undefined then "en" (English) is assumed. + +

ppd-make (text(127))

+ +

The ppd-make attribute specifies the manufacturer of the printer +(the Manufacturer attribute in the PPD file). If the manufacturer +is not specified in the PPD file then an educated guess is made using +the NickName attribute in the PPD file. + +

ppd-make-and-model (text(127))

+ +

The ppd-make-and-model attribute specifies the manufacturer and model +name of the PPD file (the NickName attribute in the PPD file). If the +make and model is not specified in the PPD file then the ModelName or +ShortNickName attributes are used instead. + +

ppd-name (name(255))

+ +

The ppd-name attribute specifies the PPD filename on the server +relative to the model directory. The forward slash (/) is used to +delineate directories. + +

Printer Attributes

+ +

job-k-limit (integer)

+ +

(CUPS 1.1 and higher) + +

The job-k-limit attribute specifies the maximum number of kilobytes that +may be printed by a user, including banner files. The default value of 0 +specifies that there is no limit. + +

job-page-limit (integer)

+ +

(CUPS 1.1 and higher) + +

The job-page-limit attribute specifies the maximum number of pages that +may be printed by a user, including banner files. The default value of 0 +specifies that there is no limit. + +

job-quota-period (integer)

+ +

(CUPS 1.1 and higher) + +

The job-quota-period attribute specifies the time period used for quota +calculations, in seconds. The default value of 0 specifies that the limits +apply to all jobs that have been printed by a user that are still known to +the system. + +

job-sheets-supported (1setof type3 keyword | name(MAX))

+ +

(CUPS 1.1 and higher) + +

The job-sheets-supported attribute specifies the available banner files. +There will always be at least one banner file available called "none". + +

printer-type (type2 enum)

+ +

The printer-type attribute specifies printer type and capability bits for +the printer or class. The default value is computed from internal state +information and the PPD file for the printer. The following bits are defined: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
0x00000001Is a printer class.
0x00000002Is a remote destination.
0x00000004Can print in black.
0x00000008Can print in color.
0x00000010Can print on both sides of the page in hardware.
0x00000020Can staple output.
0x00000040Can do fast copies in hardware.
0x00000080Can do fast copy collation in hardware.
0x00000100Can punch output.
0x00000200Can cover output.
0x00000400Can bind output.
0x00000800Can sort output.
0x00001000Can handle media up to US-Legal/A4.
0x00002000Can handle media from US-Legal/A4 to ISO-C/A2.
0x00004000Can handle media larger than ISO-C/A2.
0x00008000Can handle user-defined media sizes.
0x00010000Is an implicit (server-generated) class.
+ +

printer-type-mask (type2 enum)

+ +

(CUPS 1.1 and higher) + +

The printer-type-mask attribute is used to choose printers or classes with +the CUPS-Get-Printers and CUPS-Get-Classes operations. The bits are defined +identically to the printer-type attribute and default to all 1's. + +

requesting-user-name-allowed (1setof name(127))

+ +

(CUPS 1.1 and higher) + +

The requesting-user-name-allowed attribute lists all of the users that are +allowed to access a printer or class. Either this attribute or the +requesting-user-name-denied attribute will be defined, but not both. + +

requesting-user-name-denied (1setof name(127))

+ +

(CUPS 1.1 and higher) + +

The requesting-user-name-denied attribute lists all of the users that are +not allowed to access a printer or class. Either this attribute or the +requesting-user-name-allowed attribute will be defined, but not both. + +

Printer Class Attributes

+ +

member-names (1setof name(127))

+ +

The member-names attribute specifies each of the printer-name attributes of +the member printers and classes. Each name corresponds to the same element of +the member-uris attribute. + +

member-uris (1setof uri)

+ +

The member-uris attribute specifies each of the printer-uri attributes of +the member printers and classes. Each URI corresponds to the same element of +the member-names attribute. + + + + + diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000000..4f2d81204e --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,500 @@ + + + + An Overview of the Common UNIX Printing System + + + + + + + + +

An Overview of the
+ Common UNIX Printing System,
+ Version 1.1

+ +

July 10, 2000
+ Michael Sweet, Easy Software Products
+ Copyright 1998-2001, All Rights Reserved.

+
+ +

This whitepaper describes the Common UNIX Printing +SystemTM ("CUPSTM"), a portable and extensible +printing system for UNIX®. CUPS is being developed by +Easy Software Products, a software +firm located in Hollywood, Maryland that has been selling commercial +software for UNIX since 1993 through more than 40 distributors serving +over 80 countries worldwide. + +

Additional information on CUPS is available on the World Wide Web at +"http://www.cups.org". + +

Background

+ +

Printing within UNIX has historically been done using one of two +printing systems - the Berkeley Line Printer Daemon ("LPD") [RFC1179] +and the AT&T Line Printer system. These printing systems were +designed in the 70's for printing text to line printers; vendors have +since added varying levels of support for other types of printers. + +

Replacements for these printing systems have emerged [LPRng, +Palladin, PLP], however none of the replacements change the fundamental +capabilities of these systems. + +

Over the last few years several attempts at developing a standard +printing interface have been made, including the draft POSIX Printing +standard developed by the Institute of Electrical and Electronics +Engineers, Inc. ("IEEE") [IEEE-1387.4] and Internet Printing Protocol +("IPP") developed by the Internet Engineering Task Force ("IETF") +through the Printer Working Group ("PWG") [IETF-IPP]. The POSIX +printing standard defines a common set of command-line tools as well as +a C interface for printer administration and print jobs, but has been +shelved by the IEEE. + +

The Internet Printing Protocol defines extensions to the HyperText +Transport Protocol 1.1 [RFC2616] to provide support for remote printing +services. IPP/1.0 was accepted by the IETF as an experimental Request +For Comments [RFC] document in October of 1999. Since then the Printer +Working Group has developed an updated set of specifications for +IPP/1.1 which have been accepted by the IETF and are awaiting +publication as proposed standards. Unlike POSIX Printing, IPP enjoys +widespread industry support and is poised to become the standard +network printing solution for all operating systems. + +

CUPS uses IPP/1.1 to provide a complete, modern printing system for +UNIX that can be extended to support new printers, devices, and +protocols while providing compatibility with existing UNIX +applications. CUPS is free software provided under the terms of the +GNU General Public License and GNU Library General Public License. + +

History

+ +

The first production release of CUPS (based on IPP/1.0) was released +in October of 1999. Since then, we have released several patch updates +to the original CUPS 1.0 release that addressed security, portability, +and bugs found, but no new functionality was added to improve the +stability of the CUPS code. + +

CUPS 1.1 is based on IPP/1.1 and adds many of the functional +enhancements that have been requested by our users. As with 1.0, CUPS +1.1 will be followed by patch releases that address any problems found +with the software but add no new features. + +

Design Overview

+ +

Like most printing systems, CUPS is designed around a central print +scheduling process that dispatches print jobs, processes administrative +commands, provides printer status information to local and remote +programs, and informs users as needed. Figure 1 shows the basic +organization of CUPS. + +

+

Figure 1 - CUPS Block Diagram

+ +

Scheduler

+ +

The scheduler is a HTTP/1.1 server application that handles HTTP +requests. Besides handling printer requests via IPP POST requests, the +scheduler also acts as a full-featured web server for documentation, +status monitoring, and administration. + +

The scheduler also manages a list of available printers on the LAN +and dispatches print jobs as needed using the appropriate filters and +backends. + +

Configuration Files

+ +The configuration files consist of: + +
    + +
  • The HTTP server configuration file. + +
  • Printer and class definition files. + +
  • MIME type and conversion rule files. + +
  • PostScript Printer Description ("PPD") files. + +
+ +

The HTTP server configuration file is purposely similar to the +Apache server configuration file and defines all of the access control +properties for the server. + +

The printer and class definition files list the available printer +queues and classes. Printer classes are collections of printers. Jobs +sent to a class are forwarded to the first available printer in the +class, round-robin fashion. + +

The MIME type files list the supported MIME types (text/plain, +application/postscript, etc.) and "magic" rules for automatically +detecting the format of a file. These are used by the HTTP server to +determine the Content-Type field for GET and HEAD +requests and by the IPP request handler to determine the file type +when a Print-Job or Send-File request is received with a +document-format of application/octet-stream. + +

The MIME conversion rule files list the available filters. The +filters are used when a job is dispatched so that an application can +send a convenient file format to the printing system which then +converts the document into a printable format as needed. Each filter +has a relative cost associated with it, and the filtering algorithm +chooses the set of filters that will convert the file to the needed +format with the lowest total "cost". + +

The PPD files describe the capabilities of all printers, not just +PostScript printers. There is one PPD file for each printer. PPD files +for non-PostScript printers define additional filters through +cupsFilter attributes to support printer drivers. + +

CUPS API

+ +

The CUPS API contains CUPS-specific convenience functions for queuing +print jobs, getting printer information, accessing resources via HTTP +and IPP, and manipulating PPD files. Unlike the rest of CUPS, the CUPS +API is provided under the terms of the GNU LGPL so it may be used by +non-GPL applications. + +

Berkeley and System V Commands

+ +

CUPS provides the System V and Berkeley command-line interfaces for +submitting jobs and checking the printer status. The +lpstat and lpc status commands also show +network printers ("printer@server") when printer browsing is enabled. + +

The System V administation commands are supplied for managing +printers and classes. The Berkeley printer administration tool +(lpc) is only supported in a "read-only" mode to check the +current status of the printer queues and scheduler. + +

Filters

+ +

A filter program reads from the standard input or from a file if a +filename is supplied. All filters must support a common set of options +including printer name, job ID, username, job title, number of copies, +and job options. All output is sent to the standard output. + +

Filters are provided for many file formats and include image file +and PostScript raster filters that support non-PostScript printers. Multiple +filters are run in parallel to produce the required output format. + +

The PostScript raster filter is based on the GNU Ghostscript 5.50 +core. Instead of using the Ghostscript printer drivers and front-end, +the CUPS filter uses a generic raster printer driver and CUPS-compliant +front-end to support any kind of raster printer. This allows the same +printer driver filter to be used for printing raster data from any +filter. + +

CUPS Imaging

+ +

The CUPS Imaging library provides functions for managing large +images, doing colorspace conversion and color management, scaling +images for printing, and managing raster page streams. It is used by +the CUPS image file filters, the PostScript RIP, and all raster +printers drivers. + +

Backends

+ +

A backend program is a special filter that sends print data to a +device or network connection. Backends for parallel, serial, USB, LPD, IPP, +and AppSocket (JetDirect) connections are provided in CUPS 1.1. + +

SAMBA version 2.0.6 and higher includes a SMB backend +(smbspool(1)) that can be used with CUPS 1.0 or 1.1 for +printing to Windows. + +

Network Printing

+ +

Traditionally, network printing has been one of the hardest things to +get working under UNIX. One reason is because each vendor added their +own extensions to the LPD protocol (the previous standard for network +printing), making cross-platform printing difficult if not impossible. + +

Another reason is that you have to administer every network printer +on every client machine. In some cases you can "clone" the printer +configuration from a "master" client to each of the others, but even +that can be time-consuming and error-prone. Something better is needed. + +

CUPS provides "printer browsing", which allows clients to +automatically see and use printers from any server on a LAN. This means +that you only need to configure the server and the clients will +automatically see the printers and classes on it. + +

In addition, CUPS can automatically merge multiple identical network +printers into "implicit classes". This allows clients to send jobs to +the implicit class and have them print on the first available printer +or server. In addition, failsafe and load-balancing functions are +enabled simply by defining the same printer on multiple servers! + +

New Features in CUPS 1.1

+ +

CUPS 1.1 includes many new features and capabilities: + +

    + +
  1. Backends + +
  2. Banner Page Support + +
  3. Digest Authentication + +
  4. Directory Services + +
  5. Directory Structure Changes + +
  6. Documentation + +
  7. Drivers + +
  8. Filters + +
  9. IPP Support + +
  10. Job Persistence + +
  11. LPD Client Support + +
  12. User-Defined Printers and Options + +
  13. Web Administration Interface + +
+ +

1. Backends

+ +

CUPS 1.1 implements a new backend interface for retrieving a list of +available devices for CUPS clients. This allows administration +interfaces to query the CUPS scheduler for a list of available devices, +automatically configure printers if the device identification +information is available, and present the user with a list of available +devices rather than relying on the user to know what devices are +configured on the system. + +

The new release also includes a backend for USB printers under +*BSD and Linux. Support for USB under Solaris 8 will be provided in +a subsequent patch release. + +

2. Banner Page Support

+ +

CUPS 1.1 includes support for banner pages at the beginning and end +of a job. Banner pages may be of any file format and support variable +substitution for job titles, usernames, etc. Default banner pages are +associated with each printer and can be overridden with command-line +options by the user. + +

3. Digest Authentication

+ +

Digest authentication provides a more secure method of authenticating +access to the printing system. Unlike Basic authentication, Digest +authentication does not send passwords "in the clear" so it is more +difficult to gain unauthorized access to your system. + +

CUPS 1.1 implements Digest authentication using a special MD5 +password file instead of the UNIX password file. This file is managed +using the new lppasswd command. + +

4. Directory Services

+ +

CUPS 1.1 adds new directory service ("printer browsing") features to +make using CUPS on large LANs and WANs easier. You can now poll a +remote server for printer information and relay it to the LAN as well +as restrict what printer information is processed (e.g. to "hide" +servers, domains, or networks that you don't want to see.) + +

5. Directory Structure Changes

+ +

CUPS 1.1 now uses a directory structure that complies with the +Filesystem Hierarchy Standard ("FHS"), version 2.0. This should make +integration into existing Linux and *BSD distributions a lot easier. + +

6. Documentation

+ +

The CUPS 1.1 documentation has gone through many revisions, +including a completely rewritten administrators manual, a new +programmers manual, and an IPP implementation reference manual. + +

7. Drivers

+ +

CUPS 1.1 includes drivers for EPSON dot-matrix and inkjet printers. +As with the HP PCL drivers, the EPSON drivers don't necessarily provide +the best possible output for each printer but should provide adequate +printing quality for general day-to-day printing. + +

8. Filters

+ +

CUPS 1.1 includes new image, PostScript, PDF, and text filters. The image +filters have been upgraded to support Windows BMP and Alias PIX files. + +

The PostScript filter is now based off GNU Ghostscript 5.50. The new +filter provides much better performance with higher-resolution printers +and supports most Level 3 PostScript language features. + +

The new PDF filter is based off the excellent Xpdf software from +Derek Noonburg and supports automatic page scaling. The new filter is a +faster, smaller, more reliable replacement for the GNU Ghostscript PDF +filtering that was used in CUPS 1.0. + +

The new text filter now supports bidirectional text and can embed +fonts as needed. + +

9. IPP Support

+ +

Probably the least visible portion of CUPS is the IPP support. CUPS +1.1 implements all of the required IPP/1.1 operations and attributes +and most of the optional ones. The optional Create-Job and Send-File +operations are now implemented, allowing for better System V printing +system compatibility (one job ID per lp command) and +support for banner pages. + +

10. Job Persistence

+ +

CUPS 1.1 supports job persistence. This means that jobs are preserved +even after a reboot, a feature that was sorely missing from CUPS 1.0. + +

In addition, CUPS 1.1 allows you to keep job information after the +job has printed. The basic post-job persistence mode provides a job +history (number of pages printed, time job was printed, etc.) but does +not preserve the actual job files. This can be changed to discard all +information after a job is printed or keep the job files after printing +so you can reprint a job at some later time. + +

11. LPD Client Support

+ +

By popular request, CUPS 1.1 supports LPD-based clients using a new +mini-daemon that handles LPD requests and passes them on to the main +server. + +

12. User-Defined Printers and Options

+ +

CUPS 1.1 includes support for user-defined printers and options via +a new lpoptions command. User-defined printers are special +instances of the available printers (e.g. "printer/instance" or +"printer@server/instance") that can have their own default options such +as media size, resolution, and so forth. The lpoptions +command can also be used to set a different default printer queue. + +

13. Web Administration Interface

+ +

CUPS 1.0 provided a simple class, job, and printer monitoring +interface for web browsers. CUPS 1.1 replaces this interface with an +enhanced administration interface that allows you to add, modify, +delete, configure, and control classes, jobs, and printers. + +

Software Using CUPS

+ +

A lot has happened since CUPS 1.0 came out, and many software packages +are supporting CUPS. We have contributed code to the SAMBA team to support +CUPS, and parts of that are already available in SAMBA 2.0.6 and 2.0.7. +With any luck the final pieces that provide a complete integration with +SAMBA will be available in the next release of SAMBA. + +

Two graphical interfaces have appeared on the scene that use CUPS as +well. The KUPS project provides a KDE-based interface for CUPS and can be +found at: + +

+ +

The X Printing Panel ("XPP") project provides a graphical printing +panel for CUPS and can be found at: + +

+ +

Numerous other filters, drivers, tutorials, etc. have been made available +on the CUPS bazaar, available at: + +

+ +

Finally, our own ESP Print Pro software uses CUPS to provide drivers +for thousands of printers and can be found at: + +

+ +

Operating Systems Using CUPS

+ +

One of our goals has always been to get as many UNIX/Linux +distributions using CUPS as possible. Debian is currently providing +CUPS as part of its stable distribution, and many other distributions +are considering it in their next releases. + +

Summary

+ +

The Common UNIX Printing System provides a modern printing interface +for UNIX applications that is both flexible and user-friendly. The +software provides System V and Berkeley compatible command-line +interfaces to ensure compatibility with existing applications. CUPS 1.1 +adds many new features that make it an even better choice for printing +under UNIX. + +

Who to Contact

+ +

For more information on CUPS please contact us at: + +

    +Attn: CUPS Information
    +Easy Software Products
    +44141 Airport View Drive Suite 204
    +Hollywood, Maryland 20636-3111 USA
    +
    ++1.301.373.9600
    +
    +cups-info@cups.org
    +
+ +

References

+ +
+ +
IEEE-1387.4
+ +
System Administration - Part 4: Printing Interfaces (draft)
+ +
IETF-IPP
+ +
Internet Printing Protocol/1.1
+ +
LPRng
+ +
An enhanced, extended, and portable implementation of the + Berkeley LPR print spooler functionality
+ +
Palladin
+ +
A printing system developed at the Massachussetts Institute + of Technology
+ +
PLP
+ +
The Portable Line Printer spooler system
+ +
RFC1179
+ +
Line Printer Daemon Protocol
+ +
RFC2046
+ +
Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types
+ +
RFC2616
+ +
Hypertext Transfer Protocol -- HTTP/1.1
+ +
+ +

Trademarks

+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software Products. All other trademarks are +the property of their respective owners. + + + diff --git a/doc/overview.pdf b/doc/overview.pdf new file mode 100644 index 0000000000000000000000000000000000000000..20259176fab75ef8c435b1a8458c4a99fb305781 GIT binary patch literal 37968 zc-o}A2V7Iz(l#!jpfr^tNJokkA+*qo^xg>x5IUjPgwO;;n$iV{2nb4tBt)tZ1XPMh z7bGA>5Tpo*bWlY2g4}cNx!-;7d(Z#-FMsZ=J$q)JS+ky5d+j8I&qPB@L|jyol5g(w z;Co7OE-@}YCr?F1fC=2s1?dcf3%CdRc)R#HbBT+}ii%5csr&hd!adyF1G&WIs<$_n*@-TK%M6Bq!GmBfqJjW*ILtB7!_Qa4 zF%Tx8A%EgQ3@9cpE-NVql(7~BSa<|_!vs`)xr~E|CLXY0E1ud|;E(HfxP;pz&5!+f1#2pcX*2>`<1(HRDSg*baV`Tzouet|F-CvSi+(#Ht~ zM|imT0$lvOy&d5Ie;C{u<{Job^da^Tj=nCZ$_S!QZy3OzmI_O z9tbahzc&&Aa3+q$5#ZzDOY9R}c=)*h5Z;amcR&~n?g#Mmg#iMC{Q!aPa2O2W>W72_ zTs?wd0E9;f009ev`2t|SefoM36`lRO{d|dHACJ?XHw=LQzygqt-T=3gRKwuJ;9!W8 zlmi?C0jdBsfI2_}pb5|dXajTrx&S?ZKEMEA2rvQ|155y>05gC&zybgQSOUNR2*3(p z4RC@xI(xwae-Fut*gXyPAJRXD=j`F(>;ZR1`T&r=F2t-j`@vzv2poxVI|7^l&Hxtx zaV!8gfIGkg;0f>ocmsR@z5qXfKOg`A2Ot1}03;v?5DW+bgaX2Tdx!l45q^617o+3-Hv`k2qAI9Kg!OgGkns`2WgN7r$U% zz;8C5FwFae*3L-y38_N?p+u@U!Tr2oz9&gUz?^@x;7>Qse-tyo5ANbhWYBLyoq&78 zeEd%5+uP60!`ac>*Dny@9_sH-bO?vJd7MDOTmU|f&L`ozz}!xVdcy2eN)yS8K>p@6 z{FKCho;f-r17QFk7=R=%#r1!tX_m9wh zPsk2G;W@GE?&$4$3i%Hq;!pPfPL%2?BUMl1Q2ooitDeq<>Yv$Bg`eb7RTH58M@X8d z#+s+bntw6Y{L@PJR7dwzNB1u}x_|0u2D$@`PT`DC)s0WpjsK!<{11gct$dK)fgb+e zp#bC4`U9Psf=*3Ae=!C9X=8PI(So=(5?KX<`w&^}VE%F z_|wY8Bgo@KaGC_=(nOK{$O~r6AyxPoB{{Dpy zlBh4N?<_b#tFsuV%aT1cl{;NAU~2N}*>R|+nbGaa!Y$K{$Qb`;V0+f`29=>h%egB| zKCuUY5o2W<(DRw|Kh3? zEo@S?25GFtho;e?v%7nXQnzwQJym)zRON%F(=AaeTA>69(M1JW1<`~3Jmom_*?Lx{ zh+^|x+X^lDtE?6M2l9s+yGHtiUo4(UiGMWt3Q9+{u&(kyTbFrR*VjSp!<7JUG}>?^ zC`s8iG26uA-`hwy`qGn7S60_Ko_h2a#uecC!XEjtPp^S#H{HJemZ`e(;A$5O$Zic~ zo@YD$P&3cAGfQ(<-j{r5SHKfo;X1U?WLckt-moT!pxac@DD>hX<>#5Ai=h&ROb`u)z&=D<{wuU6#miTF_U$_fGxtOCSK?^6E4rNdij?^ zQvRm@Z2P!KGWGcJUqtHvgLMBW0&%gwQw6_?eNr!G#D$EwKQcerM%Vy!iTkw>;+gG1#q}S{?e7(?)E{LDlo6Br_pbR(7{XadKKr_T*S(w3jmq&mKEHs-&Ha?Ymx;&fBZ4ixyMfiMNBtMOD!Tzko5*I)!W^g36o%@^(7~S{ za&ss5cj11B_qRfRZp&IV2zl5>X0VK|AFJ=az_0x*vYbC^$yiB0-d+6wQSm56hNjbv z?yG=O0{w=A1GRyZ_K_r`7F9wc-KDDIAr7x|1XdR~8`txKptIB8wV531b9Y(AOBY=e z?RrQ@e*{-e^a|xWNQfJ>jYw2YL2-Y;uyWYV>6ZDG|8&nes2wd#r=$-qy0fhLt zFrx7-q2^n8W*Xos{`N4doM&Wv3UgDP8CLd*gB#VsY4Q2{9HB=;Jyl1_Iq1NaR+mxR zY^~d*qi0r+H9#nwik;A^{y}4?o|nU})eQZbChQ~kfm1dXQ2b?^4H7YWouQp0Q^MAU zU)VX14x%*bR}}mj&3ZImtg~E!YiP9+UiM1Q+mjzzjk2Dd{>Lw{e~HBwx3NTmi4yI2?Zi!z1aZ0HixoDXL3I04Go<)Yy#4a=j75T*w zu2~Mx9S}t#jDD zYRkfWYY+)01&eaOu4ehl^ExIlZ@+EQH%cw!uDqa#xVJn!4!uy5iYO~viSWIw#duI*Hhh@>!V7}`)Pk^0Z0b64VjN4v; zz7=inV869}3)P@#J|Q`W9-ye;c{V>6IK($gBdc>6t_zXk$LV zC18s2(Th38!tQDAZ?T=`g?^&_1M-eW7@>jJRyVw|M=te(ZHKWncSQ#W4loz6X?yRR zEX=!mS^_*$ocY>&(uR_`->*L755Ko!%2TPYl!x_Nd3kAd0x~M6au&kW;d#xm$~6IW zF|Pzjd_{I;@-&XyUA2*`IOj!aC0v|%Hgm#RFys-= zLb({t%G+~(V-I9lofJ_w%xZ$ z4$C(W!W=DUT|ll3gn0)iOBPL)5E^;;k4Z*zW)%u>7ynwMP`U?mGCk2Yep2)2hRZ z*m#iC@U4z69BTBdb7gJ5do4Oq;7Ahd`?Sa6<2&{(&swy()FTl4s}AjJ)7AIuRiP^? zVlpfoUbe0>XmQp#vZ^rRyz6x6zV`t9oFTL$iWOhRjCN^{Eg4^Btd2sgVtDKS?v9%PH)C*YIFX#TpN<)rg z8y6kW2J-I{FWDmYDUNAoLU~#rtjA3K2UMV+Vv3?9nDCYG9C?W)}_a}$@->)BY)sq(2t*6KWuEJshT#(M{d}~GU2ns=4#y0158&iD?aX^ zxdYp%-C0ryMOMx0#Zuqu{rNbG$VkUpp|Z+{e7IvKhlu*~mO~CdCa}5YXFC;g!-wQB zxht>OFrI`@x34<1K&UZyennv=>N!CrmCyNbB%`kjArvv|$K}s8eSaPa4F81(Q32_E zd+Nu9pDAN8nK#yVw4X}_v{d_B;tz=%z@x}d&1Hv2k)OApkqcTMm8#&0M*SsK#YDBqnhDfgdS=Qi3!0o5iveTdrxObM%)-dqlaS8*L- zxMNoy!c$WDkRK=Wibc?;o``k9(uV$6AYoO#N=wg1#1LwK2WU3o=`j~ZGOFW&A>y6E z4h>rh(~l`acuFfR`Eg^fS;T$nB?4MVM(=rGPzkGsRayo%l?G7GXrR-CCv5J35_|dm zi3L^Fz)Rk6evjBbuQQ{`)s_zoZC*DupTto6=74{^juG3d-{Kn$^uo^Y#xrC;Ix(XEDHASUI5$CIqs&*r@h00;Jlk-YXeQBep}oAoLnaM>(8LhSF{35nhM zA=&g=-3w?M@=5m%Msc>#r8`F#Mt7?7-8;pEeZIJDIT-R`gmXMmsifE~E#R}`ArgrB z+psoYHLwb*#87K&Fn%A=lkOner$g)9#JF~ovyt21X%H84CgXt+_9od@m$z{D?9VJI(2%dM!3uIl+>iku2-U_V;J`NgW z40d@Tvh&kdgwE^Z*GSAtAi=pZESnbcK+m628S^&qz*hT<1o9rPV4#j7sWAluULYwV|(cPgx-v{OA~1`p^~+Gy~;J3@B;8~nplB;Fw))7Yi6Sqv3;CWmwq3J(n!nQBVEz;r z>b$MLbr&0a&Uf>ff)KB8`K`sgQpc2a=ES<{H_Q@p1wuh(Z&N^Z7{mZ!$NUhYFp}Hj zcJH=sRK4b{J-_a(?PvO4txLl@y8%^i(mydgv#5qSugRgWJ_zkWMIb`%2jXSXkrhu{ zNfs?lR?#LvI`}JrL5e5W{CrlH*#BMXV6wBJ})D6WS7{by&Ypiw(g@j`X*@K1^ zeVX~DK^r$nm=PydH@UL;7B2*5W~^Bu(O*+ZjSY@l|HVI1gZ@$ z4c!5LbjIkO4Zlm^zxeq3bgTT^0|^-Y)CWAUm*%^SUkH9c28G;K8nJW;JT zC%A@=ew^+zFLy~my=cnG!z!}xp)SgNlicaURvsqBwPtrAkyib0s!|Dk$;t#bhsa;- zChJOGfXBem)P8Ksb4;1mL-Sifp`(_-?y~ocDg*uAiz}eR(lFnT+tM#LZH-sdYT>@<t5)QUUxe-11HPZprS6a9&b-M8gs=f)c zbOz&ZD{)#9*28!F$Ea%K?UrXGB!8hFnHqObvZM}aRlflt|x(#2_i*#f0}oxfkmA{9jXZ!(DyY&;M*m%wbp9&^x{|SR`_N9@qUWt?_!9 zS5R4wmI6C=$!Nw#7avq_l+KEIxhpS4bk#9oju7dU{$NIL#|bxfDt+;6QviJ#pDP+~ zh2J&XKpj;Y8TQwH+sJ(ZJo4F5la6)UF(?%?PJKga}RHB2{%yY6)XF?0ax*Sw6%jlI4eUlWtvE6Y2U(=!f)%=Z)ft z%q8ZZkNJ|Uy3pIi@l96>iXH{mi9s(hFFV#2(c<#FKz+6>dwoUMDYYb-c@TXLUSqx!u zP5VoiJF}%~a|&uJe~M-g#XX-kSY{SY(Vr=dM{n%aih5+H z*MrEs$gM;a9@Ah0s)9ZXL`4ylM_C}XA1>_w=fwkeY1Q#L04As66$XHX3P2EscaZ+x5)cN-}-o^j^$4^p{f4++i6#xJC@sp$&Q0#wrpWCqJu`Jyg2S>KFyk!`G zzmLt)$l*Yz_A$zI#z1@Ma@|O@4!LgBk(n7f-~Luo-D)Z)|OJG)46tTqF3y^I5&>jrz-=*bf@!o5teLGc2OFILX?K7i`E=&dfP# zjN}(!`!De!P;ba4s&CGbps1WR9##vkZy3j@ z8h?87P96Md{p5h?)b-S7xL`{|zVONq;*bSd``+YU_xkAwlxmvG9BbiG*O{(FP1#?6 z1@3weB|!T%WZEI>Wdno4n1~t5(YJM_F{ej+RYx`8+=Ei6T0Qv9toCSMl+PCAs+3WI z*#cwoOE@(OYxG!8uWAAd;w3T)J@8qrQ#hB=@57byHwH}LS1S(!IIdI7rzmm|e$33F zaD$)P{TW8WEZoX#!DyCb0qY0g8jfT!wni3HzQTQO{SZunF$o@8@Kfv8=ii?J z#l2S<8Y5kpH)^IyoA7#}%kqrTG_KZGby88UL5(>+5|2W=IX25bnn)cTuliwGbCsBy z_mvtvR7LN2JcWcVhl}$X$}*w)EEG2Gu)yoDp!68)$T*+0#D>ebOK+D1sUgnUx5$-T z=x6i}FD?D-F0;Loc})szD8k4`$48WgdoG&_nMS{Rdnd;nq|kz+@4S%0Hs6+6Uag&O z)?Surep8R;c)_`FQ9Vzk%M$6!Wxv3Ccf0=_*b$s15Y&n<76kHowlE^}uGY`#F`-;@ z_e21cp0`GVDi}>~n06IeVuJQ-Jr1l(ggn#L^Y2x&G+Sdyp+5I_(ADxEZoE;9Nb-yv zu`s!&Q?9X@U>tgYOV4S^c}z$DgesB8vw4I$|G1ryA=oWepE>M zEAJOx%uH>nG$ARRZdN<^DrctsR2s8aIB^+RO%S>#uW+Y=+vL#FIm;R=Zvs@kpXvOx zqvU%m8|WG^&QmK=*n-kL1G{Kqs6)MOoXS_CRotS+*B-M~x#Q(|bIZiplV)Vvj1)vY zZte@r9LXLYZ#{G|E$(Z2;-c-RxdtL+5~pK+9!|k(m@0& zq8zML?9CUygb2$LOu$86bcm-G{EOr1Z*MakGC@7B*yRZeUsWCd#L?rT85FBY2*kV= z=$~S~>G)9~HU{k#(^6AywM{E-vi%ELWUA1sCCJ#>pEkWh{V6r&sU+W5_nsZ*GCF?q zcdKlHib4&yMvAlwqYuQMKc%e?5^O7LF;h|ZQPMl2Mus=jt(&#a7zFf8t-4i2L}~^| z=BK&c?TPO+{PKa{;Mnm+5khvc6kZyfa~b)~-8VW)*r)3Z-kMg%U4_6bq=1qPRdDcB zp1RKrZrf`KxQ@mKlMR^Dq)X7>WNq=gkJGUcF=r#)wWp={KIXd*{h(*X6rSg4Ncw5}oRV?AqD z6yHR6mdjbV3b}3Rh1E}cHs~>B7MBZJ1PQs7cG2wGlq=7yL_y;wcPE*JBvG}szVAT0 zx5}q4)pzPmBp*cF8?m(P5z4xI>~N=s{#8as%#3-fRw9^z^U&@GD&itR4n@C>m$|J+ zs4e@z;gFD7UNN*UP4)8%TFzX%(0lOthDo<}1=R30%ht1k93juWAxKBo&Fl+LA5nU4 zrrW!e2O8!XHm@~=Q4vfm7r*#_TacFV-cs@mUU`>YL&5ug61rku{>U6%4&4*YIoD&f z@WzD3R&SKRf&Oe(Q=VylNl+5SYG;a5@h;~vo0I=BUg@neW1(m%+}^jiY`6G0 z^yToXa1R@MWQF~T^T^I|(b10Ik*;OWEfDmM!3D%hFPqOBuOVu_uPQx3Cambbx2oes zKkAtU-rp|jp^jOb8T;;YVr1Fg6MFj2Y=CkAtI?uE?IG^dnGZa|Ls(41R{x;Ila&lvrftt#Xah! zoIDDyhVMKh_sch}+P90~vSa-sb{{hGFHO+7Mso(EUV&a(D3?T2+>&$p+3?RFN6Onq1Le)Xbjq^23PZ~Q-mZRZiEmIt`S9JB7(sF`fxW(uRpZPxb zeYYe#Aiyu{5YaIfqoNCP;LLchxA58uoJuHuQI zDl)l1lXy#hJvGVdx?3Ty;lI$SYFQkxK4V8L?PD_)qe>;u;}Ws@@aE`a5c2vktBGjZ zQN_v^(-qs5-q-R*{)cRx3Ymwho?lJuk4gDB2#CD)L6ey#hT9f{gd4X@oYu`|Uf|Ae z=|$9$YE%ZE1E5pee;l=ss9CCKQR3V`&Xg@)GI z=YC%8CLkE8+@(T;({LhUR^ZFGObs>(0Iv11E1K~Ce$@v z3YU5wf#8ny?BQ6~Q7c30p1dO=bA{Q_02JZijM_P}Yyx9}h5n^bAe|bFJbz4|+v3hm zGyNuTb{Vl=p?Xd76=;bE83w{dHWHA#EnV^YcFw2DvsA!78fjeUBWMv zAta<-B&j`f6vI#*)^;z_s^Vz2h(dhzQFfHwced(mb;`jqe30_$3 zTjQr6(3AqXnh`Z`rcBV;u@t)r+-qgH4cDm(V>PSX#0?1Z*9(AVMpcV?&fplq@?A+y z5X*Dvk?DJyv&$-l8Q);_V-4sX3!ZUV1WDxsg)iMzqmua>^b#g2&n#sb$qBV>B?u%y z*>?41UrFJUe}4#(_}kz9`Te}|-@g6>R22K&B!4&Q-%aj!Q~%xmAHKo!-=2N``3)X9 zAn@OxZ1U`H72Tk}OL&BsbVK;Q?+*=n){lQtxl}Z_e=Ov;U3Nj>ZQq&1h~C!-r8Tv7 zk#;|FW`mjA-K4){vdk~9zuf=%tM@%V{BZDS@aF`+WAdm%Cvai;$8JO(bZ$S1LpOTz z*y?K5cOU128-vewts6H?Wa?DBK84-VearW8EFJMnn9eR#S+j39SAXF>8+T6imV#?O ze!8clhS0)mr+2`@IJVwl(`_{5pCGYmWydoMAEkP!zL=oj%sZ`rfC#|hbks7B zuPh#9ofWcb;T?O%3(+-B3J4ulHFmfpGphXqe?ChfgI7!Jp4oZAmU9r!stV#zMS6pl z8B3BxLT;*0Zm;OT4$*}_N)T?Gfg|2|>eA?g)|A_TI#aDgEa19?a#*XeMMHv4m@1ABhbjXe#~ zYDLQo@=roMpY-7CP#-!?xzI&AO*Uw@8_tV|Sci_tPj><3ALTi`YKaeLf2hP^SqC z^X;;h7%>oC^sgSSkW+ssiHF=#lwr*fcM(j(Tqs)Oxcl|hoX}#;>lZS@%{ofoX9)hf zx0ZNWA2UN2yv>uIgreT#o6c3ebr8%;y0KO9L^z|Q7H)tLiPbziX@bu=mwewj5txpF zQYM{$UKD_|Q{-jB`okSR`OWSY?OR)4S3m2Q-t2Z`cn!lIhuOR|Ad4z$zZ-L%pyPE6 zjpY~#5uN2I#y?E;yXPtj3547B+CS%x&SKOXr4Zs9yY%{QA9*&kuDhxo4$_x%$ro^g zh(=%aJ%}oqzk01P*HKou*nN(q3z^(Tc|oZ=0D9S-+fd$&0sNv$+g0Ghh4wgbd-Fv* zf4b+L{)_?l$Te3b&w_g|_B~{+niv3eUSr85QTTvQ)RD>`c{0^QcmssKCF#XNK`!la zJC5}!n0wxh_l?8cW>*RWy6Z$2uHg8aX4^Cqvg0tx-a!Q=*!+3A%d||s1DyQ$iSu`< z8d5Ti;oKnQJVq**<~T3-vZ;%XMXI1Ewr4OoE{CJ+f@pEi5(2Ty%SwvtdE&aH#ysa5 zEganfe9rCaij&q#*QT=enU7}HhNnBq>B2T)d?u{CFxymndI zJ5RV?W!uT63X3D|6x*>YPu&=Lc=qu!@+O=;8Jf2fe#R^QkyXYjKI%(zDIU%@X)FQzQQ3G7YiTk$p}yfI!L;v^xG9_+tSY50 zJofr6@)ve(7yMmB0aN881&#KMx5Q2LA)852pCv8I)}C9m6U_SG^`LU_ILe(7Ft{R$q%SU94Ae&#V(DnBG<#Ic@)oSSEoOym7G(*SKvVw0QKT3#IK@q(BgLwx^ z7gevl%|!!B2#4;GhC*D zimX!?z0#4sUzn2o7HJ+v2JW2v+Mslt(!JgyMC$f;8k@Dy%~vKu6b z8;i3fJChGjYZ)&z3AN-?^|^k!qFVuFbPgNGi|RdF63Wh2ApQL44xQ#gAT9|BUPLbB zJKmGNqaX;ys>6WKhy88C>{l9bK>%iM?SwDrNKva?DmmOt%#F$viT*j!ALGY+p!bw=Q(p51)fBpt;Raq2rb6VKxTViuJrm9L zjhesu>ap0=F&lzig_HE4j&99^5tqTk+A~yjKRmqyMdmy^^0U*)WFSQa__OIn$LZHgX!( z7BY^UbWA_9Cf}quxM()R+*GKBn`4chd;=cR=5DUExFQ9unXa4HWd4Lt zy)n)_-cibl_~;Fq6`H@GZx@@ezkDqKMU)%${ajP(Z-OkENfxG(NU+?=7m^mZjpQ(@ zP2)y@5*=ko%#P29++3gg%_ z>xMTP{oeR>D171>`i$jbEeMWk77z-hrnJrrp7_iQA(egVe7syfxR5-yQRZso_$l4qZRLdzV#DR- z>*wpLe1q~$Ml5gApe4V|#kbcF!I1~s3(;$>J7>rxIReFJ{rRkMX1Bk+nyDL_#0bhD z-*uARU41(1`9_FBpy9D2UOIkb;pyidIVe6J!>pn;2nELg7Y1mW9tAYkh>w-I7aMne z{6@0y5Fs_DI*3|nj34`90xeRA3YJs(`JiFWRazFe#yhrfJl&(Q{Mr(EqdwKE45{g< znCQ-{kUiKgeKU?#L1Ao7^Ly@4Mf;2fo`WkmpnaAF=*dXo|5Ns+j}zx5sF`)5d`H?; zz9SPo?O1tw*q6ZG&m16Ex;0Qa(Ybjlu0U!C z;6xHJgrCnwFKK(=wz(VMq$EQtujBMs{hF29?yE9&js3U;{j3!?dbyx6h*>l}nIROO zSBM|DOB}BR9C#?Ex6-~Q%yRJyvSd-7Gu~@N2Y2*cgJG;97E`aE?4Y zW9gh6dtot>-s@>ivdsf`=UAkL$UV@(xM5bXHEUzB321rllRRgt*SmXzC~o|4%+6%4 zeXGx{uRFGE(53bO8WvQBlQ1-nQ&jNSBvl4C$$@W8idhYp#iobr6iCb_?X3ba`SI!FiLHDNG)o+R} z$a6l__p$KE*i>npfZ>H`vxdt<9}B5ShcYdB%0cybxc6&Xx>!Yf^)5oA+e@T{IG5~? z=}5us8TzdQcNdA!McX~hjV!cT6YiHTJY*8hT98P@JX&0lg?jQJVUIbBK4svxXYu4I znIss@RlL!ns3n_deR_`8StildJ*}0uApWf@YnGfF=0u&No}^A!4&2Y&Gt{;WCxpB` zY#B>|3+b8UJKlKN^>e8b>eYRRaVt-?%CELkv|+yo6p4sHRNnF0*2Hfi;fyoTKmHM` zMrKR~9D?h}TXkNDX$9+5ytpy;vR9#R7;F$Mh-6v}yJ}}|ZZFN-;%HT>L|?@JL99#f5Y>ev{&sG%EC z;E0%+V=B+pw#0p8gFdyf&e}T5TI@%?BGLG~MFQCF&)8HXaeqm*ptzfQRiY72FpKs_ zKA|u+hTHxi)Tg}<^RXodmxc#2;}#=L1R`}gg>*mhyil{r8YINeql@WRKexZo5nW9W z_btavE{@$shc&;CofqP}b1BVg_ub9qxW4!%DcnwE_&c<=(cIyt;qWMdFJNJ-XtF85 zYWU*%@sv_TW*)C)eV}#^G^+#IdW^hn@Zu>ndzo`U(adaf#8M?6(`-1r&7getvyj2E zY=h*2QM4exS?~t5YjQ^6c)?r@=fxW$(UFoZk&=wmg%S+o2Oio{d~V7^DnHpF8RdI0 zXFiZZys+^$((tDPbpKMs$mA-M3PT1!dW-;1p;rJf^!v2te+0{l3Ua!A>!MSkJA5+<+^U)kOJ=Um-!gsZjH!D%2jw-5Ob3B~lQ24gc~| zghKy9VC#+K?2-imOeZw!6=8;Ld!b>rk=&}zLy4uE%`~eGiR@!)V9U@C8+xc$@H0cs z+?H~TAl|^l$(gabeeJ72mR^>(ycJUyQE#oJl{E{vzG`2P3oO|y__8|pYpauHbm_SC ziYVs~Z$H3iO+#nM{FfEF#+;;cc2n>WoVK4#jLAwYTK`j%{9=+#e$1*lgT&|J>^}rS z^KGp*b$M4}Dw@uUZZ3B|M+7L*JzImuG@Zp^oLdv;d9(DD_kMsRC<#3{V^?pja7n+#N2-#f+Xo_Nf*Xu57c?D2b z8$rpE>;Y7C|I#y`_bO@Xl`%v;9FbVl&-q5oRVi?JyKH*_=RNFh7!gYRb=Tu)xyUFq6)ia_)a!ft=ulEDuhCKQp#T>^H7&%3(98h!?ldk!f_T z18vYB?Dm=vha62MiIu$+Q~TsvOgg~G#zLxMZ!@q$Bw)#`L@j_3LnZ57aCYyOpEH%L zUTy^U%QD&LdC%KQDc-K5Qbj)Lm_VzZN2x=8iERDs=b@6dW*b{+O>3>DC37gO{K6&) zDWh@d1Il-W*Y&VD%=5`pSXzIibC^;Mq{UXHl0NOM;G5SG)s+{6dHW}vYn{xs&Dca-)G5_xzK4kfnpXRbdExS&+{ED8~5 zdLiO&mB_0UZws}VYjtP*Dd|z~$gb&7Kndlst!jac_tjY+yvsWOo^;+KS+EfB_1o$L zeXP!xb6QOWU6j9qfbfv}jXk^Pono@Zqp0!M=sGBi{NFjpDO)A6l}dnLaHwiry|Uw8 zkjAU_)#NfKu{Q|5cGo7GihC#hJjK(mlwo!6w6C#gXVRXrR&u_aN?Lu8(U^nMFtg-t zJzp?r$<2!IiTlu`3+85>Bmv`TX9fI)&U~l1tl7bR|03r`JZqeP zoeqF1_KNsVs?+G(zZs+`g&tg=;EZc=NB?cNsykR zuJ_K{Ofch9H(9Rv{5%(SaCTDDGai29tV>qweQs$fb?eyu3xSy{nFR-`kwWj+NpenMS*2WGTBKU$u2gL z_NXWsT{qMLk8>N@_GX{JZuIt}J3oULspy1LKa+fu%JX{#dC%ThBR?568&<37&y9*K zB@u=UGJn7AnNQ*zf8o`WifwAhYpT_#wew3?tKydp?f_J4&$7Q29Qxdt3aL_OYp+*@ z*QZlI5@=MF-7$)n{f;hysnL8CVhWQ{r*87U5{|hu-G3>@Q)zGc+dF88I<)|MWlaCg zb_-p|2ik-zys;~!CE#2k#5wF z-F%qWr{t`uWPcuTnHw;q)|^w$e{{^)JG7e~eK%osCg~SXxWDm&rw-Yoxq?6r>H%J( z=F%g9sq1IHi^HEd6z*&keClRXB)2FIZE^M=Ql2e3l&NJfik1K57_3@D84NmH=+b!A z6-MA;rs-w77?t(wTzB5%#SRI5#_x&4-yBrj%-WXQ9X84haVx5CavD>}j}(vFv#FGY*Y-O~M-aUJiX&db=-SkWkf_v2zhw#e7ADk>W$+BeI9QgUC;>bL?2H@aR~Z z4SV@x%bL=F^)^1b$WSdS=l!;ys}$Eo?~*7C)`D~8TE#1F^in8f^+wqaP50ma8T|U_ zg@U%|iiCmJ{b%b%0rY-9+ZF`NQ4OrXZ>E*`plXH%m412nnri4|LxX70nvlsRyA%^i{uWxOKI_;y8F3Wn)r9&DrRS?l-txiZU{ za=Tx<9e^zLFyJ-hEnQL3YSrmJ32gE z4A)z3MZM*5%&}6d4!4b8+dtA(F?zPnts)~ehWs=j!?p)7UfOD&dD;4s;`psq;}wAo z6^_cRfq(zV;GaKwU=9G8>7M)-a1RXhmj?iXgM&q3j)+i1u&A@2&p&@fNBo~ZZ}7(_ z3kDv(UH~(gbD)i+gtVwE7f|}-C?zQ_D#rzskrS1*1*rMKU0`sVlRr=vvjwPf{YL)h zAO4F2|Mx(gk^Tr#Ke*dp!jS&o!jO{_73TtqONokcNy*BIN^=1vWJJaOhcJNu8pc0< z(ZJ^SAk9ue%xwR-D*L}c%198gB*evuM{y#qESH3Y)W0KYzz~5pvcJa;fLK{``69i& zxn!ioiP!!agxr6F5tox80*FfkMS(;}v479+{|F;32K+0GgxG(Dk(DB5PFz}+IE^Qe z(tisEC?WYTFyj9eMn+sziZ~Neq7uI$rT!L-l$hARz)1X87@+J40C600zab_57L25r z)W5(;{#O_&;K@-^?qr6DkbjQ?5|aNqH&XukT!idYB zP(VzKSWYL9|EIUFfU0Wi+7?i01*9A4J{_na9TEb9(s>B!4(Sj{>FyK|0TGark`_fu zKuQ_`0qGEako&&(>hZhYJO1%~j=|yVdFI~pS!>NXpEWsaE&m4>fd1srFvJgLV81nU z(vA}s0G&GYsY%E`GINqzelP?7of#zP)B{e22KwD1=pR{uAb#}c-zI^Rgm=;+7~sqx z;2#+QL*PFc`E3d~iT%?Qa}tz{aK!&K`ac-~!G9PQFyKGQ4sn+3zMlzkmKT)H;#TP_ zu9VLFUg^v)mCpP|>1}3g1o(6epr@};B;;2t z2mX=ez`tQRYZDhf2TN04eLWXjl!Ltq-|4Afrsn4S&eqm{fd>0MG%)xip1`LJ#0Z7_ zBBh={`;qy;@P9_Y{Q7#XdV02e2F9j;L4^1%qLU~(9cB3GC_|8tUvcqw2!BC@{HJph ze(Te70IhAU{zL=;{2mbydD2IJAOZt^*+a8_W?Gw zw&piIT@1o^dg$X{TJd*e0fwFCB-rT~e~$_n{Fg)g9m8K*0sDJMdUp1Dw)WqL*xcII z()edY@ZTajd4-+eI(>osVghr52=*f)#NQ&~b+FUpGqtkR`;O`KC_HmLOaA*7dUjTp z{MP2yKLbSm4&Yf1fkIDbsJ~7j-x2-gG%cbO^5-st-<+8P<0{s4g|bY$=Rm&^tQ z{uUGzei9j{v~n_&NBk-=uhXSLH;Eu z81QFMzx8-10P+U`pA;L=U-=jGM~{d8;qe-fGYW;AaVO-AdZA~W3q2#-@8xPF&~5C;#cWw@eM~G@xfZ{O9L?`l76r}4u`q5At&rRbPlUOPJTTLD)n|rhx#W*I%b^{-O^28}-vV>L+#3->9F~ zLqDm5|3>|^uK7tF@;BAYq9zSIDb4=K z;3pplTUuJ3meH1`BN{t>I|{Cb)wK@Kk@U9Nd><^Q9G|R+Ec#%)ZaE26<-{aGp3GA2-YNzmPsPL&%`S#CWMhK?b1Yb zc}f~U8)`zD?3%U8faN2ywZy#dc=&mFV|hDbpQ!QX+=r3kSKr<<3s-R_-!qK#lb1f4 z&#u6GEZF>sgJ7zU{HDv5$}O9|UQ)pfN#b3fkR+T}gz{}}1b86t>%sAEOkXaKWMz#1MYZ?8QqvyD^TP*t)i_ z8T8WEQM3q7CsvhPzaUS3)o+N31>)fju?33-KAp{YMy{4~rGu71qy{j1UycR~Bfb~% z)q+eAAs6G2ZnG$>7f9o^LPKya(Qi%pezMQ>HD$v^`5chRZH7zwA#sY=Tb>N3M@{Q$ z3PE4?;;_+&#zIss`JU6`4t0k6q~X-dMYO0sd2@wa$5zK(uYU7F*kZ6IQG@dq<(FKe zHnaJ!LJIPZHCo}(RfMvot{H&h0$OJh31Hb}>-7FtT@#OHJTCOu@4qZ(1Wgh!*_y1T z*qW*AT#v)S!sI9rOAk@0Q_5nE859jtxGwMXP{7?Ne^uF?Iru?B#|!_l@E1Jr`*jADBGy=>NPd{F};fXm~GiD z*z}sy60YNIM@qIC0@N}`G3{`@3AaP1n0j#0(?E`1(uWm{kR{Y;eQZPt>TO?Ow_`2M zOP=->yTuDMODY2|iKYuw;h=Y7SK&%ETmn08K7y2w$hgmc-Ewuzx_curL*}Xqb=osy zryJ@?DTaefxwn`2IK)5F@iEm!(kHXFU)|N{5g@L*_k@6_Siksc0hUYTxrwrIF*Y8r z2LGD4rb?zux^jpovuhVeKKMS~Xu4_~&m~*fw0ts0wdfxtFu$V+;dRY^Uyd#sX&Re z^4^ohO*H&0*JRQK_A06qtt7Xj$J-DwS-N(R-ui&!azP`4dO~;_*Tkp`>lKvvNkg*T ziuPO*XT$;%>7?I>k95t^EFh~_f4_s;DIMXf@wVayw+@iwWJ++CE0T0iWmB@}(%9uUxEsHB_yTiuV=H?MU zsbKQ?gMY72Afb9#@j#HotG=(Y0>jNyQ9fOpy+#^EcX1b&I0u`>8C#TKIIjmWoUJGcO5aSZI&W3#|{)MzYWb_wr~@Hrl+RD2Ztm zFbUz)_>!%vE5;g6mR`B`sm&GZ@ieAqtXDDp;8Gz=s^F^t=CW^%B-uVzql+SxcrvPm zDg-q7FV9s{+{cs@#woD`1uGZS7-QSuRZcMy6sGHit!7xr%=ul&wXsLiJZ z+s*PFZOL;;(?gzGXm6ct`uo;W5!EAXj&g+qJo*2cV6l$8rN8>XkKNrCqMz2evNMChi@XZz#hU1<`(z|${FSS3$+^T`d- zi)IM z9!Mp|_q$ZX&!y<})c+~YPUh1A4JShhXCw)6tB;9&BvR zu=>p<<2{!2!SP}xWWJ-WPWYn{N4l$hIq&>Kfz$6nlkFKh6fIt}4-_lNTJ&|2T{j8i zdR^(m&v~w8)}&Q8T-EYpwCh*; zl|*J1TW{iWN1rLjhkEQ3{)KeX%pGrpep9V-mCCiw`*dw3jwPwp6y{4cyuWW= zM=+4paKsDSI`0&z$m~00M*{rZC$`9C@(Nb~XXEnyotlnqW2t)=)4pCOxZLZdiZKX@ znW4+k6T73vv}IqCMzT4^tL{U(UhKQ3ors@%a1J3QVTZS5mEo)Q=fxc)8&U zpdBj+5-6O0^e7WMuv0kSkhBn^lUe=(@)N={vC`)8ALGD1(Y-Iff-;0LVp0nMd zlq@L2iXv+sUb$8=nNPB|H&<9}yXeZ8mPY$9O!Ov&7bkr_oSNBMWtvcFuRpq2_fUG0 zww8L^h2M<*5WA?tFgg8Womk^h3+CbSW~_W4m`32RIj*s0Erf#KQ}X!ZEXr?^^e zb}*SQL!bD?dELXVj4cOvUq4rIe2znzc!K<-2m3)>06#-x9pviF2RxdRBN>SZPoZzr z6!Q;hh7k(~4J}IywO6iF-(uJRPQt4E}$rRE|HgbG+1v+ z$?kg$8hQ}-pE_^h54M0RBntgq~D?Kj%*OyK;6P z5d?MfcXi!ljLlo*`&jBM64^{0N1i!NEiW@sBxW+Rk>*E6*B$NPhxZ4dYNBrOC^cZM zt)2TOkkCkaY-H_liGklcj$MbG-FSxrkkqK}&mQ;TZb`ddqFkQxy|q4Zru64Z5A?hj zXB^cjQ~&wi@&9Z2emUbz6nx&~XzTaz0-dfm@fo)YkRZ9YOvb z%La~N=j5vtWvstWHaw*^*!`SlwAg?f`h}px4|^gYrj*9WE}{=ZSWP-OeH%lXF047p zpd@#2?{#8MKNb%69NuP{u&akhf>w{6OvmFk2B*o&7|Pbw&jp}C=Ai8$-#BIdqYdL2 zeWl0VDlw7Cisr^KHsdzj+(H*Wxom%BV!40k`P~jlteX{VcPZIRMv_Q)t#kXy3qNtH z>_Z<~@X#yv-a8kE!KlwJ5_vzMJ@%vZ`bT|Wo9qa5?!2;usySzQy69IoN6+Ej%ob}i zK){FsIpw|De(QPCI@}m+x0>QK!BO6aPMn>MMOIF5oq!KdZ|>^`HGT6tuo1LM74?2M zfN{w5HT;|KCAfc2e7yHkLmRG=*@CA~EW5XTmE@9Sx{v)XKZR{*!nl;q@`EnI;#)HM zJOiok2G;xq4G4Cc6p|}_VtnC`!7((UDvtfdVwux&!PuqUbRrX{X zwGCL3bQH{svx$p>AH1in%tw=}W7kZiwP^8T5J}W<2-o{zixdjh>X_Q}D=C=5f<1L? zkB8om6Szxq1D}|rAbUj8ZyH*+_2?2@=JX@h?;y?8%;KRWA)F_Odjn^U9!hcoXgd3Kh&66RWlPKkC7}_ZLh;VK)g`T^N$<}2$!H3wJmX2q~ z?Fgy@r(ogf8oHFMV$Mk>Q-R|eRQ>+`XUZ4rYpPj$$Psru+kRzDNbvavADXdYb}!$O z3#`z(*e$PcMw2Xd?2tBLpYv}v0CIo|KIJEGid#y^oVBVBtWgSzwQbgB3V{sIneuI~ zVcK$kV5%^g0l(pke4FAKR#oesD%9A0X!8MI>*al=G0hAm*E^0Bsj`}^FEypdBa#g& z?x#GYLitKuCFW?zaBQNk#asPotRJtD&&)axpvL*(i( zrsM6JEoO)bDcc7!BVUZm?rO)}MR)(98K8Ox!5`WSBEr)qS_kcOcg7wly-MV2Gw^c~f+IAUK>dG?(;XG^3 z&*VU9u$kWmD6OXhMphKIzASUEGB)%~>f8t4uQj{e_Y|GxP;J|F?UQAi zSuRAe63J#~KvA>|^xq~`gN5&u=Q*&@wsc=IESok}z36XQ5Z)O2Ir{~Rslwh6P1GIn ztRy6=;E9rwoyvS231$^#!29D}2iY4IHSF51{>PuIHK*ht&2s*}Z1;OKMhjf!qoQzn z`%|w*jVaY%ak@U9HS2B#HC5qMwE8%~sh^>bh`%~o*!ME0tuD|oA&bLlZu3(#9Tke| z@JUQu%*a@hc~PJjSsB9CKXaGJN_#`X-E*Kfi0$q9{WU`&%vhyL!|YOtO0L7(FBr(z zI1eB#LH7Gxqaa42xL)vO~_fK*-wB~jLW2MezEuHsP|b) zhw$6$w^qoJvo#X+@}bw0w2UdzjIH-f$w$;^In3 zgpjk{o$vcJWn*)r`<RBduFDyHjvfy}}VTF*z#~jS~^Tf5C~M|36Or9TooP4}stx zzi~o<{s}R{U|=+2483g~{qD8u;>tiX{0*Hl>0XuZCjz?%m#;~$m_`?r6VJuqMF|y(sgEo>XclNr zbHbx>wYskuaZBsPyl|JX^`MwHwKQka50w1I6WSs`BA_>KO%>|Hbj@MoP!$way&M%P z-g#~JTXJ3#ht`x<8r+apNgceZK6i-W}1DEld|?^36>c2q-YFOwa(&uc@SzN&d^glD1lB9m5S%VPO%U<`~W)X6XS z10G4`GOAPWe(sz8oU7o;x4Lg%|5X1KUyw=|uZ-(w_vqOa(9qsu!7P?Z=+l^p@Lp{J zMIsj^L~nkczQec0xy1Xp1ipZH0rqR=a&464PHzwc@LT6Oh- zTG76+D={5K6mg(_=FM%h@iXX;h)>L3KD4iG7u;kpL&91w& zzVS^6!@cq9!kCW&>e_k{is$AzY2wuefvX@E5_u9g4$-|}wmluratBjCitW%tJ6IR( z1>7%tDthUqZdQsKQWPb~R|Qhl1qD;C)t|Ej>Bfg<1}_EOiM|&LjbOiDrnoLBo?+8&#zVcaek}D(~XA+6%&9Lg|E(T z^#{WZf^X9IhFK$Sl*IE*lj2shybG8h5-(BwSVx?!JraN2*Pb8z;VPdQ|IIm)+c|^& z-fU&#aUl|wvm-WI1+teWo4}04iF_$85y^+mV+HoM(^8*x>#Q)7u<^}U%I7m6MIIZsj925 z(#@TteLB>w**uxOqzQS* zwR3w9qoemLDM3#(`=ku;T{d_| zQ9XuRcZ242_7ySG>cl{i*f@qde1GmLLYBunhlFe3;S~BBZCNc0S&FTV2Obn$GiA;&<822jeH(U$}*7;}5T(y=b`f)Tkx zfAE821=Vj;ls$%XFW^)k-jSvI`sV;lW%G#S=IG=+-h6m5!+%k;z@A4TBT?UOLaNz7 zce+%0%5Ts5-K8PDnRsegtkIpg;YNGBug#Or1p-O&aW z7x2s_fq)Te4X~d@Q?-?OH&KQ7`3PF`Jbh~MlqTobrZ-+rE7Q*(J$EnLS9%%TxW^c< z^`XC3;3dU|Zs{WvfgNNUUD~Vbc73mHw8mnsHh7u|ed--9>8QVO^(P07n>Dz*hTOPV zmSL59=t!GUDrYoqu~UDoVO@vf7|VEe;0Zd_g8v28LjI4a_NV`o4f0Q@76L`DK|}9O z*iplYJm!msKILQ^@X@wX3hhgd8nVfmG)6hH@lVNnOBwi$D&r)Ez1rroXPay zFd0O;@Nm+}M;1o4^cg=5W5*V%b=?rI})EhtgYgnvcJ@N4(s$G{rlm1k*T-j|a$v|Uq)XzJ?fGwoj!?{oUDUM`MQ1V}AN z7(P~-=No}aT`bXKtos*A(_5WaPuoD`<@2L2 zVej8cd1ZvgT$krny)BIJf^Hr^jSiGz;Jg&jLiJGwWaQ5zU0lU z-hmxIqX8p>r$X`Ag@fM4xkTieat#uSJwEv`jkV4o5vjYp$zqO;A0>9p$8^oOU9InI zgbzH0o|9{lfpK_nEziY&Ilpyvf4JfDTL$IIaPAz3+pw@sd+UmYBsJP8i36qOz3a6F zJ4FWkD#Umf^l>c{(>210Bj3(%cit7gMR4H=mmkjrmaP#SSuc~uYR?{*$>oO62jWi# zCy;2*747oeh{SXoL=td-ID(0-a>}^^DtyH<(w@Jzt-nnjO!IKYq*RDwHAXXiW0W&} z-CnCv^Pu{UcDsZHcj^!;$?x_+O$4y%d3`SSH= znG@SGCwHoQzguv*UWGw!aox*W&37iHv?}Xa&_IlEM#U}7YpDk}&!rTy?w>dANK##n zX=s(PBQ+SP4?kKz|3G;-u5+s@_wf2uXN&wYjKr2>VW%b-%Mwrh4mFdQZq(zowZ&!~ z-e`s8D|kgnOH{s@319K_ZguEumdl@6c7o)rBZRu$iz7a8b5WNDJ$+Lv9F-gCAp2iB~&rWfJ9DC%{lBI;Mp7q%9Fyu^7w*@K9-+6?x3VlX1TJ*}?i zP3{ZZC|wkqCm9z0R+1c^R(vDjDarPzR#s*;lzuaU*5EQVf|;?em-+qUFv(Ek3;HU@ zK9nK{s&3A}mwY1qnJ<;|HFG z16D=8HsQS4i_IigF^{HPG$9LxXlI)eB+9DVkkt<|&3BUpbaW`dd#Jh8sJgT7DHjcD z#yn^@E!@2=WkG9Gdgc7v>^3MS`L)8@xN3I_r1r}YLa27&)YDhn!pf7GJhO{NHf%`qE+ulYrk;!54g3aOJ+Rfsjz%~B%r_*p5lIVUf+#jzmm&He6h{y>uq|z zjHN3@wQ0SZ+XmA!Ars|~p12Px>hqd(u=<-4VlM67nYh&B4sS)aD39LpP;M!F9i@kF z0qHG(A2;0KyAl7fZPC9?WY2xAJd$$5WV&i-r*3h2qVbuYqf%dNZj_;YOz$q29NY4q zdfzgA~b*TOw@TD8p??t$zJ|J?*8`y(&N=L1c#^si&Fd8qHzse%1!V zu(YfqIxYQ+6(R`O|1K^4Nkso>@dp?IMAmS<+(NWI{=7Uo_k^f}~Oepc8D zTY%>DzOCcLb;M&-$J<}!!I@=1~Cw#1&UND+Y zKT$sA*v&6rBF2kK-nKYcMZ(K)VuF_(p@UD!C^Reg@Vstlhv~w4V_OGB<|AR9#U?qi z+@^V|0?OsuRG}O)0ne#C?vjgKh1bQIsl8w4o0M5V(X>Z4RcCaB zZ7TcBeeXBUPY6lW13ge=LXentRCj#Cy_-l&OfKr2P~7kJzppGRo{-!)1rd zPXG|lCqQNY=b-tyM_hacmuxen2dOgSB*0`m_P92!1T|ntN?M!dJnk4DxjloZ5cnp( z8OVB#^!_sz=ge~3Ahl0gPl=UVT^m^Vr{d{G{VF!@!c`cFh6;jq*3`M{%Q^BWfdNF4 zwH-GzeC))&;jR{Ss`F2$3Hxg?_SuI}^465nX=|xHQItOhs0}&tI{^L7+7)}p3{3>f z1ifNg{PdCtoubHy<^#W^r6(mGh1oSRXt_ltRSTEMs&opypBHV&U+Ypc!d zC?_2emopGHENm>fRrBy@5-(A#V;N@?4!-z>%Te~xJF8yhAks2%< zcrA5_=49mi(+eFh0EYWqs4HvSbl3SfpiTO9YjI=`S@t!E$*^dYkcKOVq!XTyu2gJ} z;&2ULG9a}ebywXW@5T4eL84asv{$|sgeAcB=ZiL7e6~eC+@Taq4`Imr(oWbe{zc&-%@?ur1zJI?Ca?wsA2jCZbuJ``T(1p5FK zL>qnqP*4wZqb$b|<>lbdS=b2{;eus=A!}ZGmf^9GR>v>HkrfzCvyoODt}QEAVc$e5 zxJB>oq|mCq+X0sBKrrlLHWzd)?ek+1w=oYD9o;qu@03bWb=f~~xP(2Y)~1%2%E~^^ znexiLnV1ja?ln1xC)&rkhxhG5f7`Xuaf&*u){Qh#xdWWO$_=Uj#B3!yJA23QVRTc{ zH&0a$PsHxhq>f-0AQ7EN{>6#~1mgduzJdI>DF^Y7)+d1A=<5?=RJ$BcXl3kxd(Ln+ zS)G*gJxPoTozO@!q*S9rntb>s3kwq)2KhPOGMx#0FV}lv?#WRIV$|EEw<*^)Rux5n zM=TKf9&0fdhfNR1{`$n*pxj~1dMXrdH(pQ{BFr?FL1CcjS;CyXnV)9w-b(l8$}+aB zl1!v-FHJ}maY)#^CwF31-%RE`tD3pc$T2@26v>gBtde}kK;cn`4;PyTDCr!uYjr4+ z#`bbn>DshJe-8mLT=ksE3(erq{3FtYoWyvRj3HWRjD$o-TnJEkFT{Intpv(3L=V{m6; z;m#+&E(sMBDH^D|=}Mrc>d;YSXSJsU=8n!Tw|jHf{8bt6wj^Qe$4n`{&_S2GzM4ac0`F#NBI6 zk~@SldyN|w(k35-pE2~GneV-M-Ox};`-}@Os7n6ZPRkE)K)9Z#guQ=cpN{=movPR zWf%53_Il*#{?&>vQ$;m|-4CpBG;b7mP0@^*M9=TKG_&w89;_!>!Qob~>c8RMd~o9l zT(!K?m5h(x-##)UkBm?r`(xhSjBt6jR04(D_liF#*4@vNz}qYws4XpgGU<+gahu_D z^)Y_9nh@ zz+8oGkAw4MB}|T^@rEDsK4e77r#7=VEuZ7vXL5_?Z{cUOnKi06S4g)_>{sud-DI=A za9ofwqSqw*gaorZBH$9A0)7o(p*WsnaGcP>3n1+GnE9~AD%+J zC2rbu6!me}t5^zo?hYQ`YM=AQ(`yRz>ZP816*xOy6a&P39kk%{?m`rHI-aOY7BsHH zyoT+@^Hy>jHQZ$qgB!v-zAL;{0P@FR8=i(EkV&nhw*QTgFOtFwlKNIY?W@J+lhiXF zBX`L9R>~L!J_+1a@u#xeU1s5d=2tItb-0p;>zK->=t3XoO`kvp1|r! zk)ppSrl_NvtPUF?ycu z4}2kh*UMC2;m0yKj>EQEJc8+U^go+ExFqr>h^=yNG6y2p>-W}g8~XzV#z_hOMaO>+}7o-Nt~SN5T90&5YLIHUh{W&mqsEoP*LaMcC;MUY>U*G9;=<(ZL`4}bG18> zEE|HZ)56QfyYoAaK}2e?k)Fn*WZ!n)9}Bz*Oh8Zd|6(Nt@?Wi_`1cDa{*&sVKkn{A z{*&bta0rMIJ=Lo;+KvE->Ndz8uz*Vqs0>6cSy&0d84g#Ba|1N*Jivfg%*gme*ROWs z>4Ge!de_N77uOJfpPe4qj)!x|h{M=*@c89T z|ErSj5#O@kP*U0@XvgmYXSa>}7W)l+6{jTm*j?XcV3~|vw&?9srFp8S)Stsqt~eU4 zsEBE6&Ldb>*q{x+Bvx?2#E@^(NTfbqYRjzv>5$o`dG_#$W7BG!Yx7qr7 zuHFCuXQAsto;QJyV>@>I<;ARfslGN>&$R^gk&(xF)e{Ca9Zh9=NpLlL-oZhQ-MN__lm*?|u=KIxFz%NVJg!4ii&1KnGW?W47YjDhC^^zhOCB%euEV zfH$~$L!RNSzL0lORPsJwvNP^U+RqRR);DvFJFMqqb?|S8Oiay z&<3V;=kZg#z5N{SLTJY$b7{E3X1sifMP8k?T7G2mh5XceY}OHNeMeRPo%0e@Bus`u z_;Q2Q3@~TE$D_*xhlQ3-Q0C+pj?s7`X?hPJbv1+ZjqD3_Fr|*G9_3ZV`t&GpMs{ALWPcLNk zT&x`I`ISvAjm=Si#Jw>}?lh=W>`?MnmZ(3}^ik%gu`cgmVW$E3zA;ZsP*CeHHNLYg z$_Vdt-#jB8;J^PEVNfU-%4qbb?DW`<@1I!yR|Y!W`Te5|2uH%vWC%FA9`bbm-H$R5 z;B-IxPcq=?VGuvd5NKFHpwlVlk1{ae^emAdWk>+%=X-%5(CIhbKgtjgbUg$F4o8zg zPdB3dB!dBeAw#0y3kRXg5Wm2J1pnMNAQAwEp~-+?B$^BaLBoOsL(tlWgg_8zGAI;? zCWApCXfiky9SZ`A);1&(`m+rX0PqVL5Uo!^0Q50GaTl~P2LZq!^yh(*=(6ueO#CE+ zLLg`|7zl|jLjurba5y?X1X_H607xLZ4I~WhULXM7E)a<3S0^%byFd_np8~;X{sIC* zfao?L==}_Y!qA@w1EaMA2nWK^W$68U5)9~AkRbHuA)&v}L!e;+q5JrW41v}*&@cJ` z1V+bq;#L538CvXvKu~ndASha{1A$;bbj&dHF$clX#}@>LqPGJ9KyL>Eirx++0IeNh z00>PFeByyW%b)=Cd!axCTH9b?7~1n-P!O6P;un630E2(-7cc+-hoH$o;Gg>*41~jg zXfh=5XUt$Q7>+K3qUBRC1cB!FU?>1BCxW4fzqZ%jR?pNNWs7%8tER4~6AtB9va+&g zM4s*Gm9{jpV*KN+n8tO85!}$|lz{*+6bK3d=|fQ<7zzS50wa(pJs?8x_Zla>jraY4 UhVP^eh9cnzJXTh51qr1 - Printing System Overview + +

This chapter provides an overview of how the Common UNIX Printing System +works. + +

The Printing Problem

+ +

For years the printing problem has plagued UNIX. Unlike +Microsoft® Windows® or Mac OS, UNIX has no standard interface or +system in place for supporting printers. Among the solutions currently +available, the Berkeley and System V printing systems are the most +prevalent. + +

These printing systems support line printers (text only) or +PostScript printers (text and graphics), and with some coaxing they can +be made to support a full range of printers and file formats. However, +because each varient of the UNIX operating system uses a different +printing system than the next developing printer drivers for a wide +range of printers and operating systems is extremely difficult. That +combined with the limited volume of customers for each UNIX varient has +forced most printer vendors to give up supporting UNIX entirely. + +

CUPS is designed to eliminate the printing problem. One +common printing system can be used by all UNIX varients to support the +printing needs of users. Printer vendors can use its modular filter +interface to develop a single driver program that supports a wide range +of file formats with little or no effort. Since CUPS provides both the +System V and Berkeley printing commands, users (and applications) can +reap the benefits of this new technology with no changes. + +

The Technology

+ +

CUPS is based upon an emerging Internet standard called the Internet +Printing Protocol. IPP has been embraced by dozens of printer and +printer server manufacturers and is supported by Microsoft Windows +2000. + +

IPP defines a standard protocol for printing as well as managing +print jobs and printer options like media size, resolution, and so +forth. Like all IP-based protocols, IPP can be used locally or over the +Internet to printers hundreds or thousands of miles away. Unlike other +protocols, however, IPP also supports access control, authentication, +and encryption, making it a much more capable and secure printing +solution than older ones. + +

IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") +which is the basis of web servers on the Internet. This allows users +to view documentation, check status information on a printer or server, +and manage their printers, classes, and jobs using their web browser. + +

CUPS provides a complete IPP/1.1 based printing system that provides +Basic, Digest, and local certificate authentication and user, domain, +or IP-based access control. TLS encryption will be available in future +versions of CUPS. + +

Jobs

+ +

Each file or set of files that is submitted for printing is called a +job. Jobs are identified by a unique number starting at 1 and +are assigned to a particular destination, usually a printer. Jobs can +also have options associated with them such as media size, number of +copies, and priority. + +

Classes

+ +

CUPS supports collections of printers known as classes. Jobs +sent to a class are forwarded to the first available printer in the +class. + +

Filters

+ +

Filters allow a user or application to print many types of files +without extra effort. Print jobs sent to a CUPS server are filtered +before sending them to a printer. Some filters convert job files to +different formats that the printer can understand. Others perform page +selection and ordering tasks. + +

CUPS provides filters for printing many types of image files, +HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript +and image file Raster Image Processor ("RIP") filters that convert +PostScript or image files into bitmaps that can be sent to a raster +printer. + +

Backends

+ +

Backends perform the most important task of all - they send the +filtered print data to the printer. + +

CUPS provides backends for printing over parallel, serial, and USB +ports, and over the network via the IPP, JetDirect (AppSocket), and +Line Printer Daemon ("LPD") protocols. Additional backends are +available in network service packages such as the SMB backend +included with the popular SAMBA software. + +

Backends are also used to determine the available devices. On +startup each backend is asked for a list of devices it supports, +and any information that is available. This allows the parallel +backend to tell CUPS that an EPSON Stylus Color 600 printer is +attached to parallel port 1, for example. + +

Printer Drivers

+ +

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes sample printer drivers for Hewlett-Packard +LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, +and Stylus Photo printers. While these drivers do not generate optimal +output for the different printer models, they do provide basic printing +and demonstrate how you can write your own printer drivers and +incorporate them into CUPS. + +

Networking

+ +

Printers and classes on the local system are automatically shared +with other systems on the network. This allows you to setup one system +to print to a printer and use this system as a printer server or spool +host for all of the others. Users may then select a local printer by +name or a remote printer using "name@server". + +

CUPS also provides implicit classes, which are collections of +printers and/or classes with the same name. This allows you to setup +multiple servers pointing to the same physical network printer, for +example, so that you aren't relying on a single system for printing. +Because this also works with printer classes, you can setup multiple +servers and printers and never worry about a single point of failure +unless all of the printers and servers go down! diff --git a/doc/references.shtml b/doc/references.shtml new file mode 100644 index 0000000000..4b4930e574 --- /dev/null +++ b/doc/references.shtml @@ -0,0 +1,42 @@ +

References

+ +

CUPS Documentation

+ +

The following CUPS documentation is referenced by this document: + +

    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan +
  • CUPS-IDD-1.1: CUPS System Interface Design Description +
  • CUPS-IPP-1.1: CUPS Implementation of IPP +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.1: CUPS Software Design Description +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual +
  • CUPS-SSR-1.1: CUPS Software Security Report +
  • CUPS-STP-1.1: CUPS Software Test Plan +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual +
  • CUPS-SVD-1.1: CUPS Software Version Description +
+ +

Other Documents

+ +

The following non-CUPS documents are referenced by this document: + +

diff --git a/doc/sam.html b/doc/sam.html new file mode 100644 index 0000000000..5a45b1dace --- /dev/null +++ b/doc/sam.html @@ -0,0 +1,4634 @@ + + + +CUPS Software Administrators Manual + + + + + + + +

+

CUPS Software Administrators Manual


+CUPS-SAM-1.1.7
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - Building and Installing CUPS + +3 - Printer Management + +4 - Printer Classes + +5 - Client Setup + +6 - Printing System Management + +7 - Printing with Other Systems + +A - Software License Agreement + +B - Common Network Settings + +C - Printer Drivers + +D - List of Files +
+
E - Troubleshooting Common Problems + +
+

Preface

+

This software administrators manual provides printer administration +information for the Common UNIX Printing SystemTM ("CUPS +TM"), version 1.1.7.

+

System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+ + +

Document Overview

+

This software administrators manual is organized into the following +sections:

+ +

Notation Conventions

+

Various font and syntax conventions are used in this guide. Examples +and their meanings and uses are explained below: +

+ + + + + + + + + + + + +
Example   Description
 
lpstat +
lpstat(1)
   The names of commands; +the first mention of a command or function in a chapter is followed by +a manual page section number.
 
/var +
/usr/share/cups/data/testprint.ps
    +File and directory names.
 
Request ID is Printer-123 +   Screen output.
 
lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are +written using the period (.) to indicate the decimal point.
+
+ + +

+

Abbreviations

+ The following abbreviations are used throughout this manual: +
    +
    +
    kb
    +
    Kilobytes, or 1024 bytes +
     
    +
    Mb
    +
    Megabytes, or 1048576 bytes +
     
    +
    Gb
    +
    Gigabytes, or 1073741824 bytes +
     
    +
    +
+

Other References

+
    +
    +
    CUPS Software Programmers Manual
    +
    A programmer guide for interfacing with and/or extending the CUPS + software. +
     
    +
    CUPS Software Users Manual
    +
    An end-user guide for using the CUPS software. +
     
    +
    +
+

1 - Printing System Overview

+

This chapter provides an overview of how the Common UNIX Printing +System works.

+

The Printing Problem

+

For years the printing problem has plagued UNIX. Unlike +Microsoft® Windows® or Mac OS, UNIX has no standard interface or system +in place for supporting printers. Among the solutions currently +available, the Berkeley and System V printing systems are the most +prevalent.

+

These printing systems support line printers (text only) or +PostScript printers (text and graphics), and with some coaxing they can +be made to support a full range of printers and file formats. However, +because each varient of the UNIX operating system uses a different +printing system than the next developing printer drivers for a wide +range of printers and operating systems is extremely difficult. That +combined with the limited volume of customers for each UNIX varient has +forced most printer vendors to give up supporting UNIX entirely.

+

CUPS is designed to eliminate the printing problem. One +common printing system can be used by all UNIX varients to support the +printing needs of users. Printer vendors can use its modular filter +interface to develop a single driver program that supports a wide range +of file formats with little or no effort. Since CUPS provides both the +System V and Berkeley printing commands, users (and applications) can +reap the benefits of this new technology with no changes.

+

The Technology

+

CUPS is based upon an emerging Internet standard called the Internet +Printing Protocol. IPP has been embraced by dozens of printer and +printer server manufacturers and is supported by Microsoft Windows +2000.

+

IPP defines a standard protocol for printing as well as managing +print jobs and printer options like media size, resolution, and so +forth. Like all IP-based protocols, IPP can be used locally or over the +Internet to printers hundreds or thousands of miles away. Unlike other +protocols, however, IPP also supports access control, authentication, +and encryption, making it a much more capable and secure printing +solution than older ones.

+

IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") +which is the basis of web servers on the Internet. This allows users to +view documentation, check status information on a printer or server, +and manage their printers, classes, and jobs using their web browser.

+

CUPS provides a complete IPP/1.1 based printing system that provides +Basic, Digest, and local certificate authentication and user, domain, +or IP-based access control. TLS encryption will be available in future +versions of CUPS.

+

Jobs

+

Each file or set of files that is submitted for printing is called a +job. Jobs are identified by a unique number starting at 1 and are +assigned to a particular destination, usually a printer. Jobs can also +have options associated with them such as media size, number of copies, +and priority.

+

Classes

+

CUPS supports collections of printers known as classes. Jobs +sent to a class are forwarded to the first available printer in the +class.

+

Filters

+

Filters allow a user or application to print many types of files +without extra effort. Print jobs sent to a CUPS server are filtered +before sending them to a printer. Some filters convert job files to +different formats that the printer can understand. Others perform page +selection and ordering tasks.

+

CUPS provides filters for printing many types of image files, +HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript +and image file Raster Image Processor ("RIP") filters that convert +PostScript or image files into bitmaps that can be sent to a raster +printer.

+

Backends

+

Backends perform the most important task of all - they send the +filtered print data to the printer.

+

CUPS provides backends for printing over parallel, serial, and USB +ports, and over the network via the IPP, JetDirect (AppSocket), and +Line Printer Daemon ("LPD") protocols. Additional backends are +available in network service packages such as the SMB backend included +with the popular SAMBA software.

+

Backends are also used to determine the available devices. On +startup each backend is asked for a list of devices it supports, and +any information that is available. This allows the parallel backend to +tell CUPS that an EPSON Stylus Color 600 printer is attached to +parallel port 1, for example.

+

Printer Drivers

+

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes sample printer drivers for Hewlett-Packard +LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, +and Stylus Photo printers. While these drivers do not generate optimal +output for the different printer models, they do provide basic printing +and demonstrate how you can write your own printer drivers and +incorporate them into CUPS.

+

Networking

+

Printers and classes on the local system are automatically shared +with other systems on the network. This allows you to setup one system +to print to a printer and use this system as a printer server or spool +host for all of the others. Users may then select a local printer by +name or a remote printer using "name@server".

+

CUPS also provides implicit classes, which are collections of +printers and/or classes with the same name. This allows you to setup +multiple servers pointing to the same physical network printer, for +example, so that you aren't relying on a single system for printing. +Because this also works with printer classes, you can setup multiple +servers and printers and never worry about a single point of failure +unless all of the printers and servers go down!

+

2 - Building and +Installing CUPS

+

This chapter shows how to build and install the Common UNIX Printing +System. If you are installing a binary distribution from the CUPS web +site, proceed to the section titled, Installing a +Binary Distribution.

+

Installing a Source Distribution

+

This section describes how to compile and install CUPS on your +system from the source code.

+

Requirements

+

You'll need ANSI-compliant C and C++ compilers to build CUPS on your +system. As its name implies, CUPS is designed to run on the UNIX +operating system, however the CUPS interface library and most of the +filters and backends supplied with CUPS should also compile and run +under Microsoft Windows.

+

For the image file filters and PostScript RIP, you'll need the JPEG, +PNG, TIFF, and ZLIB libraries. CUPS will build without these, but with +significantly reduced functionality. Easy Software Products maintains a +mirror of the current versions of these libraries at:

+ +

If you make changes to the man pages you'll need GNU groff or +another nroff-like package. GNU groff is available from:

+ +

The documentation is formatted using the HTMLDOC software. If you +need to make changes you can get the HTMLDOC software from:

+ +

Compiling CUPS

+

CUPS uses GNU autoconf to configure the makefiles and source code +for your system. Type the following command to configure CUPS for your +system:

+
    +
    +./configure ENTER
    +
    +
+

The default installation will put the CUPS software in the /etc +, /usr, and /var directories on your system, +which will overwrite any existing printing commands on your system. Use +the --prefix option to install the CUPS software in +another location:

+
    +
    +./configure --prefix=/some/directory ENTER
    +
    +
+

If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a +system default location (typically /usr/include and +/usr/lib) you'll need to set the CFLAGS, +CXXFLAGS, and LDFLAGS environment variables prior +to running configure:

+
    +
    +setenv CFLAGS "-I/some/directory" ENTER
    +setenv CXXFLAGS "-I/some/directory" ENTER
    +setenv LDFLAGS "-L/some/directory" ENTER
    +setenv DSOFLAGS "-L/some/directory" ENTER
    +./configure ... ENTER
    +
    +
+

or:

+
    +
    +CFLAGS="-I/some/directory"; export CFLAGS ENTER
    +CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER
    +LDFLAGS="-L/some/directory"; export LDFLAGS ENTER
    +DSOFLAGS="-L/some/directory"; export DSOFLAGS ENTER
    +./configure ... ENTER
    +
    +
+

To enable support for encryption, you'll also want to add the +"--enable-ssl" option:

+
    +
    +./configure --enable-ssl
    +
    +
+

SSL and TLS support require the OpenSSL library, available at:

+ +

Once you have configured things, just type:

+
    +
    +make ENTER
    +
    +
+

to build the software. + +

+

Installing the Software

+

Use the "install" target to install the software:

+
    +
    +make install ENTER
    +
    +
+
+ + +
WARNING: +

Installing CUPS will overwrite your existing printing system. If +you experience difficulties with the CUPS software and need to go back +to your old printing system, you will need to reinstall the old +printing system from your operating system CDs.

+
+
+

Running the Software

+

Once you have installed the software you can start the CUPS server +by typing:

+
    +
    +/usr/sbin/cupsd ENTER
    +
    +
+ + +

Installing a Binary Distribution

+

CUPS comes in a variety of binary distribution formats. Easy +Software Products provides binaries in TAR format with installation and +removal scripts ("portable" distributions), and in RPM and DPKG formats +for Red Hat and Debian-based distributions. Portable distributions are +available for all platforms, while the RPM and DPKG distributions are +only available for Linux. +

+ + +
WARNING: +

Installing CUPS will overwrite your existing printing system. If +you experience difficulties with the CUPS software and need to go back +to your old printing system, you will need to remove the CUPS software +with the provided script and/or reinstall the old printing system from +your operating system CDs.

+
+
+

+

Installing a Portable Distribution

+

To install the CUPS software from a portable distribution you will +need to be logged in as root; doing an su is good enough. +Once you are the root user, run the installation script with:

+
    +
    +./cups.install ENTER
    +
    +
+

After asking you a few yes/no questions the CUPS software will be +installed and the scheduler will be started automatically. + +

+

Installing an RPM Distribution

+

To install the CUPS software from an RPM distribution you will need +to be logged in as root; doing an su is good enough. Once +you are the root user, run RPM with:

+
    +
    +rpm -e lpr
    +rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER
    +
    +
+

After a short delay the CUPS software will be installed and the +scheduler will be started automatically.

+

Installing an Debian Distribution

+

To install the CUPS software from a Debian distribution you will +need to be logged in as root; doing an su is good enough. +Once you are the root user, run dpkg with:

+
    +
    +dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER
    +
    +
+

After a short delay the CUPS software will be installed and the +scheduler will be started automatically.

+

3 - Printer Management +

+

This chapter describes how to add your first printer and how to +manage your printers.

+

The Basics

+

Each printer queue has a name associated with it; the printer name +must start with a letter and can contain up to 127 letters, numbers, +and the underscore (_). Case is not significant, e.g. "PRINTER", +"Printer", and "printer" are considered to be the same name.

+

Printer queues also have a device associated with them. The device +can be a parallel port, a network interface, and so forth. Devices +within CUPS use Uniform Resource Identifiers ("URIs") which are a more +general form of Uniform Resource Locators ("URLs") that are used in +your web browser. For example, the first parallel port in Linux usually +uses a device URI of parallel:/dev/lp1. + +

+

You can see a complete list of supported devices by running the +lpinfo(8) command:

+
    +
    +lpinfo -v ENTER
    +file file
    +network socket
    +network http
    +network ipp
    +network lpd
    +direct parallel:/dev/lp1
    +serial serial:/dev/ttyS1?baud=115200
    +serial serial:/dev/ttyS2?baud=115200
    +direct usb:/dev/usb/lp0
    +network smb
    +
    +
+

The -v option specifies that you want a list of +available devices. The first word in each line is the type of device +(direct, file, network, or serial) and is followed by the device URI or +method name for that device. File devices have device URIs of the form +file:/directory/filename while network devices use the more +familiar method://server or method://server/path + format.

+

Finally, printer queues usually have a PostScript Printer +Description ("PPD") file associated with them. PPD files describe the +capabilities of each printer, the page sizes supported, etc., and are +used for PostScript and non-PostScript printers. CUPS includes PPD +files for HP LaserJet, HP DeskJet, EPSON 9-pin, EPSON 24-pin, and EPSON +Stylus printers.

+

Adding Your First Printer

+

CUPS provides two methods for adding printers: a command-line +program called lpadmin(8) and a Web interface. The +lpadmin command allows you to perform most printer +administration tasks from the command-line and is located in +/usr/sbin. The Web interface is located at:

+ +

and steps you through printer configuration. If you don't like +command-line interfaces, try the Web interface + instead.

+

Adding Your First Printer from the Command-Line

+

Run the lpadmin command with the -p option +to add a printer to CUPS:

+
    +
    +/usr/sbin/lpadmin -p printer -E -v device -m ppd ENTER
    +
    +
+

For an HP DeskJet printer connected to the parallel port this would +look like:

+
    +
    +/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER
    +
    +
+

Similarly, an HP LaserJet printer using a JetDirect network +interface at IP address 11.22.33.44 would be added with the command:

+
    +
    +/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER
    +
    +
+

As you can see, deskjet.ppd and laserjet.ppd + are the PPD files for the HP DeskJet and HP LaserJet drivers included +with CUPS. You'll find a complete list of PPD files and the printers +they will work with in Appendix C, "Printer +Drivers".

+

Adding Your First Printer from the Web

+

The CUPS web server provides a user-friendly "wizard" interface for +adding your printers. Rather than figuring out which device URI and PPD +file to use, you can instead click on the appropriate listings and fill +in some simple information. Enter the following URL in your web browser +to begin:

+ +

Click on the Add Printer button to add a printer.

+

Managing Printers from the Command-Line

+

The lpadmin command enables you to perform most printer +administration tasks from the command-line. You'll find lpadmin + in the /usr/sbin directory.

+

Adding and Modifying Printers

+

Run the lpadmin command with the -p option +to add or modify a printer:

+
    +
    +/usr/sbin/lpadmin -p printer options ENTER
    +
    +
+

The options arguments can be any of the following:

+
    +
    +
    -c class
    +
    Adds the named printer to printer class class. If the +class does not exist then it is created.
    +
    -i interface
    +
    Copies the named interface script to the printer. + Interface scripts are used by System V printer drivers. Since all +filtering is disabled when using an interface script, scripts + generally should not be used unless there is no other driver for a +printer.
    +
    -m model
    +
    Specifies a standard printer driver which is usually a PPD file. A +list of all available models can be displayed using the lpinfo + command with the -m option. A list of printer drivers +included with CUPS can be found in Appendix +C, "Printer Drivers".
    +
    -r class
    +
    Removes the named printer from printer class class. If the +resulting class becomes empty then it is removed.
    +
    -v device-uri
    +
    Sets the device for communicating with the printer. If a job is +currently printing on the named printer then the job will be restarted +and sent to the new device.
    +
    -D info
    +
    Provides a textual description of the printer, e.g. "John's +Personal Printer".
    +
    -E
    +
    Enables the printer and accepts job. This option is equivalent to +running the enable(1) and accept(8) commands +on the printer.
    +
    -L location
    +
    Provides a textual location for the printer, e.g. "Computer Lab +5".
    +
    -P ppd-file
    +
    Specifies a local PPD file for the printer driver.
    +
    +
+

Deleting Printers

+

Run the lpadmin command with the -x option +to delete a printer:

+
    +
    +/usr/sbin/lpadmin -x printer ENTER
    +
    +
+

Setting the Default Printer

+

Run the lpadmin command with the -d option +to set a default printer:

+
    +
    +/usr/sbin/lpadmin -d printer ENTER
    +
    +
+

The default printer can be overridden by the user using the +lpoptions(1) command.

+

Starting and Stopping Printers

+

The enable and disable commands start and +stop printer queues, respectively:

+
    +
    +/usr/bin/enable printer ENTER
    +/usr/bin/disable printer ENTER
    +
    +
+

Printers that are disabled may still accept jobs for printing, but +won't actually print any files until they are restarted. This is useful +if the printer malfunctions and you need time to correct the problem. +Any queued jobs are printed after the printer is enabled (started).

+

Accepting and Rejecting Print Jobs

+

The accept and reject commands accept and +reject print jobs for the named printer, respectively:

+
    +
    +/usr/sbin/accept printer ENTER
    +/usr/sbin/reject printer ENTER
    +
    +
+

As noted above, a printer can be stopped but accepting new print +jobs. A printer can also be rejecting new print jobs while it finishes +those that have been queued. This is useful for when you must perform +maintenance on the printer and will not have it available to users for +a long period of time.

+

Managing Printers from the Web

+

The Web interface is located at:

+ +

From there you can perform all printer management tasks with a few +simple mouse clicks.

+

4 - Printer Classes

+

This chapter describes what printer classes are and how to manage +them.

+

The Basics

+

CUPS provides collections of printers called printer classes. +Jobs sent to a class are forwarded to the first available printer in +the class. Classes can themselves be members of other classes, so it is +possible for you to define very large, distributed printer classes for +high-availability printing.

+

CUPS also supports implicit classes. Implicit classes work +just like printer classes, but they are created automatically based +upon the available printers and classes on the network. This allows you +to setup multiple print servers with identical printer configurations +and have the client machines send their print jobs to the first +available server. If one or more servers go down, the jobs are +automatically redirected to the servers that are running, providing +fail-safe printing.

+

Managing Printer Classes from the Command-Line

+

Run the lpadmin command with the -p and +-c options to add a printer to a class:

+
    +
    +/usr/sbin/lpadmin -p printer -c class ENTER
    +
    +
+

The class is created automatically if it doesn't exist. To +remove a printer from a class use the -r option:

+
    +
    +/usr/sbin/lpadmin -p printer -r class ENTER
    +
    +
+

To remove the entire class just use the -x option:

+
    +
    +/usr/sbin/lpadmin -x class ENTER
    +
    +
+

Managing Printer Classes from the Web Interface

+

The Web interface is located at:

+ +

The Add Class and Modify Class interfaces +provide a list of available printers; click on the printers of interest +to add them to the class.

+

Implicit Classes

+

A noted earlier, implicit classes are created automatically from the +available network printers and classes. To disable this functionality, +set the ImplicitClasses + directive to Off in the cupsd.conf file. You +will find more information on doing this in +Chapter 6, "Printing System Management".

+

5 - Client Setup

+

This chapter discusses several ways to configure CUPS clients for +printing.

+

The Basics

+

A client is any machine that sends print jobs to another machine for +final printing. Clients can also be servers if they communicate +directly with any printers of their own.

+

CUPS supports several methods of configuring client machines:

+ +

Manual Configuration of Print Queues

+

The most tedious method of configuring client machines is to +configure each remote queue by hand using the lpadmin + command:

+
    +
    +lpadmin -p printer -E -v ipp://server/printers/printer ENTER
    +
    +
+

The printer name is the name of the printer on the +server machine. The server name is the hostname or IP +address of the server machine. Repeat the lpadmin command +for each remote printer you wish to use.

+

Specifying a Single Server for Printing

+

CUPS can be configured to run without a local spooler and send all +jobs to a single server. However, if that server goes down then all +printing will be disabled. Use this configuration only as absolutely +needed.

+

The default server is normally "localhost". To override the default +server create a file named /etc/cups/client.conf and add a +line reading:

+
    +
    +ServerName server
    +
    +
+

to the file. The server name can be the hostname or IP +address of the default server.

+

The default server can also be customized on a per-user basis. To +set a user-specific server create a file named ~/.cupsrc and +add a line reading:

+
    +
    +ServerName server
    +
    +
+

to the file. The server name can be the hostname or IP +address of the default server.

+

Automatic Configuration of Print Queues

+

CUPS supports automatic client configuration of printers on the same +subnet. To configure printers on the same subnet, do nothing. +Each client should see the available printers within 30 seconds +automatically. The printer and class lists are updated automatically as +printers and servers are added or removed.

+

If you want to see printers on other subnets as well, use the +BrowsePoll directive as described next.

+

Specifying Multiple Servers for Printing

+

If you have CUPS servers on different subnets, then you should +configure CUPS to poll those servers. Polling provides the benefits of +automatic configuration without significant configuration on the +clients, and multiple clients on the same subnet can share the same +configuration information.

+

Polling is enabled by specifying one or more +BrowsePoll directives in the /etc/cups/cupsd.conf + file. For information on making these changes, see +Chapter 6, "Printing System Management".

+

6 - Printing System +Management

+

This chapter shows how you can configure the CUPS server.

+

The Basics

+

Several text files are used to configure CUPS. All of the server +configuration files are located in the /etc/cups directory:

+
    +
    + + +
    classes.conf
    +
    This file contains information on each printer class. Normally you +manipulate this file using the lpadmin command or the Web +interface. +
      + +
    +
    client.conf
    +
    This file provides the default server name for client machines. +See Chapter 5, "Client Setup" for more +information. +
      + +
    +
    cupsd.conf
    +
    This file controls how the CUPS server (/usr/sbin/cupsd +) operates and is normally edited by hand. +
      + +
    +
    mime.convs
    +
    This file contains a list of standard file conversion filters and +their costs. You normally do not edit this file. +
      + +
    +
    mime.types
    +
    This file contains a list of standard file formats and how to + recognize them. You normally do not edit this file. +
      + +
    +
    printers.conf
    +
    This file contains information on each printer. Normally you +manipulate this file using the lpadmin command or the Web +Interface. +
     
    +
    +
+

Restarting the CUPS Server

+

Once you have made a change to a configuration file you need to +restart the CUPS server by sending it a HUP signal or +using the supplied initialization script. The CUPS distributions +install the script in the init.d directory with the name +cups. The location varies based upon the operating system:

+
    +
    +/etc/rc.d/init.d/cups restart ENTER
    +/etc/init.d/cups restart ENTER
    +/sbin/init.d/cups restart ENTER
    +
    +
+

Changing the Server Configuration

+

The /etc/cups/cupsd.conf file contains configuration +directives that control how the server functions. Each directive is +listed on a line by itself followed by its value. Comments are +introduced using the number sign ("#") character at the beginning of a +line. Since the server configuration file consists of plain text, you +can use your favorite text editor to make changes to it. + +

+

Server Directives

+

The cupsd.conf file contains many directives that +determine how the server operates:

+ + + +

AccessLog

+
+

Examples

+
    +
    +AccessLog /var/log/cups/access_log
    +AccessLog /var/log/cups/access_log-%s
    +AccessLog syslog
    +
    +
+

Description

+

The AccessLog directive sets the name of the access log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +access log file is stored in "common log format" and can be used by any +web access reporting tool to generate a report on CUPS server activity.

+

The server name can be included in the filename by using %s + in the name.

+

The special name "syslog" can be used to send the access information +to the system log instead of a plain file.

+

The default access log file is /var/log/cups/access_log. + +

+

Allow

+
+

Examples

+
    +
    +Allow from All
    +Allow from None
    +Allow from *.domain.com
    +Allow from .domain.com
    +Allow from host.domain.com
    +Allow from nnn.*
    +Allow from nnn.nnn.*
    +Allow from nnn.nnn.nnn.*
    +Allow from nnn.nnn.nnn.nnn
    +Allow from nnn.nnn.nnn.nnn/mm
    +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
    +
+

Description

+

The Allow directive specifies a hostname, IP address, +or network that is allowed access to the server. Allow + directives are cummulative, so multiple Allow directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: +

+ + + + + + +
mmnetmask +mmnetmask
00.0.0.0 +8255.0.0.0
1128.0.0.0 +16255.255.0.0
2192.0.0.0 +24255.255.255.0
...... +32255.255.255.255
+
+

+

The Allow directive must appear inside a +Location directive. + +

+

AuthClass

+
+

Examples

+
    +
    +AuthClass Anonymous
    +AuthClass User
    +AuthClass System
    +AuthClass Group
    +
    +
+

Description

+

The AuthClass directive defines what level of +authentication is required:

+
    +
  • Anonymous - No authentication should be performed + (default.)
  • +
  • User - A valid username and password is required.
  • +
  • System - A valid username and password is required, +and the username must belong to the "sys" group; this can be changed +using the SystemGroup + directive.
  • +
  • Group - A valid username and password is required, +and the username must belong to the group named by the +AuthGroupName directive.
  • +
+

The AuthClass directive must appear inside a +Location directive. + +

+

AuthGroupName

+
+

Examples

+
    +
    +AuthGroupName mygroup
    +AuthGroupName lp
    +
    +
+

Description

+

The AuthGroupName directive sets the group to use for +Group authentication.

+

The AuthGroupName directive must appear inside a +Location directive. + +

+

AuthType

+
+

Examples

+
    +
    +AuthType None
    +AuthType Basic
    +AuthType Digest
    +
    +
+

Description

+

The AuthType directive defines the type of +authentication to perform:

+
    +
  • None - No authentication should be performed + (default.)
  • +
  • Basic - Basic authentication should be performed +using the UNIX password and group files.
  • +
  • Digest - Digest authentication should be performed +using the /etc/cups/passwd.md5 file.
  • +
+

When using Basic or Digest authentication, +clients connecting through the localhost interface can +also authenticate using certificates.

+

The AuthType directive must appear inside a +Location directive. + +

+

AutoPurgeJobs

+
+

Examples

+
    +
    +AutoPurgeJobs Yes
    +AutoPurgeJobs No
    +
    +
+

Description

+

The AutoPurgeJobs directive specifies whether or not to +purge completed jobs once they are no longer required for quotas. This +option has no effect if quotas are not enabled. The default setting is +No. + +

+

BrowseAddress

+
+

Examples

+
    +
    +BrowseAddress 255.255.255.255:631
    +BrowseAddress 192.0.2.255:631
    +BrowseAddress host.domain.com:631
    +
    +
+

Description

+

The BrowseAddress directive specifies an address to +send browsing information to. Multiple BrowseAddress + directives can be specified to send browsing information to different +networks or systems.

+

The default address is 255.255.255.255:631 which will +broadcast the information to all networks the server is connected to. +

+ + +
NOTE: +

If you are using HP-UX 10.20 and a subnet that is not 24, 16, or 8 +bits, printer browsing (and in fact all broadcast reception) will not +work. This problem appears to be fixed in HP-UX 11.0.

+
+
+ + +

+

BrowseAllow

+
+

Examples

+
    +
    +BrowseAllow from all
    +BrowseAllow from none
    +BrowseAllow from 192.0.2
    +BrowseAllow from 192.0.2.0/24
    +BrowseAllow from 192.0.2.0/255.255.255.0
    +BrowseAllow from *.domain.com
    +
    +
+

Description

+

The BrowseAllow directive specifies a system or network +to accept browse packets from. The default is to accept browse packets +from all hosts.

+

Host and domain name matching require that you enable the +HostNameLookups directive.

+

IP address matching supports exact matches, partial addresses that +match networks using netmasks of 255.0.0.0, 255.255.0.0, and +255.255.255.0, or network addresses using the specified netmask or bit +count. + +

+

BrowseDeny

+
+

Examples

+
    +
    +BrowseDeny from all
    +BrowseDeny from none
    +BrowseDeny from 192.0.2
    +BrowseDeny from 192.0.2.0/24
    +BrowseDeny from 192.0.2.0/255.255.255.0
    +BrowseDeny from *.domain.com
    +
    +
+

Description

+

The BrowseDeny directive specifies a system or network +to reject browse packets from. The default is to deny browse packets +from no hosts.

+

Host and domain name matching require that you enable the +HostNameLookups directive.

+

IP address matching supports exact matches, partial addresses that +match networks using netmasks of 255.0.0.0, 255.255.0.0, and +255.255.255.0, or network addresses using the specified netmask or bit +count. + +

+

BrowseOrder

+
+

Examples

+
    +
    +BrowseOrder allow,deny
    +BrowseOrder deny,allow
    +
    +
+

Description

+

The BrowseOrder directive specifies the order of +allow/deny processing. The default order is deny,allow:

+
    +
  • allow,deny - Browse packets are accepted unless + specifically denied.
  • +
  • deny,allow - Browse packets are rejected unless + specifically allowed.
  • +
+ + +

BrowseInterval

+
+

Examples

+
    +
    +BrowseInterval 0
    +BrowseInterval 30
    +
    +
+

Description

+

The BrowseInterval directive specifies the maximum +amount of time between browsing updates. Specifying a value of 0 +seconds disables outgoing browse updates but allows a server to receive +printer information from other hosts.

+

The BrowseInterval value should always be less than the BrowseTimeout value. Otherwise +printers and classes will disappear from client systems between +updates. + +

+

BrowsePoll

+
+

Examples

+
    +
    +BrowsePoll 192.0.2.2:631
    +BrowsePoll host.domain.com:631
    +
    +
+

Description

+

The BrowsePoll directive polls a server for available +printers once every BrowseInterval + seconds. Multiple BrowsePoll directives can be +specified to poll multiple servers.

+

If BrowseInterval is set to 0 then the server is polled +once every 30 seconds. + +

+

BrowsePort

+
+

Examples

+
    +
    +BrowsePort 631
    +BrowsePort 9999
    +
    +
+

Description

+

The BrowsePort directive specifies the UDP port number +used for browse packets. The default port number is 631. +

+ + +
NOTE: +

You must set the BrowsePort to the same value on all +of the systems that you want to see.

+
+
+ + +

+

BrowseRelay

+
+

Examples

+
    +
    +BrowseRelay 193.0.2.1 192.0.2.255
    +BrowseRelay 193.0.2.0/255.255.255.0 192.0.2.255
    +BrowseRelay 193.0.2.0/24 192.0.2.255
    +BrowseRelay *.domain.com 192.0.2.255
    +BrowseRelay host.domain.com 192.0.2.255
    +
    +
+

Description

+

The BrowseRelay directive specifies source and +destination addresses for relaying browsing information from one host +or network to another. Multiple BrowseRelay directives can +be specified as needed.

+

BrowseRelay is typically used on systems that bridge +multiple subnets using one or more network interfaces. It can also be +used to relay printer information from polled servers with the line:

+
    +
    +BrowseRelay 127.0.0.1 255.255.255.255
    +
    +
+

This effectively provides access to printers on a WAN for all +clients on the LAN(s). + +

+

BrowseShortNames

+
+

Examples

+
    +
    +BrowseShortNames Yes
    +BrowseShortNames No
    +
    +
+

Description

+

The BrowseShortNames directive specifies whether or not +short names are used for remote printers when possible. Short names are +just the remote printer name, without the server ("printer"). If more +than one remote printer is detected with the same name, the printers +will have long names ("printer@server1", "printer@server2".)

+

The default value for this option is Yes. + +

+

BrowseTimeout

+
+

Examples

+
    +
    +BrowseTimeout 300
    +BrowseTimeout 60
    +
    +
+

Description

+

The BrowseTimeout directive sets the timeout for +printer or class information that is received in browse packets. Once a +printer or class times out it is removed from the list of available +destinations.

+

The BrowseTimeout value should always be greater than +the BrowseInterval value. +Otherwise printers and classes will disappear from client systems +between updates. + +

+

Browsing

+
+

Examples

+
    +
    +Browsing On
    +Browsing Off
    +
    +
+

Description

+

The Browsing directive controls whether or not network +printer browsing is enabled. The default setting is On. +

+ + +
NOTE: +

If you are using HP-UX 10.20 and a subnet that is not 24, 16, or 8 +bits, printer browsing (and in fact all broadcast reception) will not +work. This problem appears to be fixed in HP-UX 11.0.

+
+
+ + +

+

Classification

+
+

Examples

+
    +
    +Classification
    +Classification classified
    +Classification confidential
    +Classification secret
    +Classification topsecret
    +Classification unclassified
    +
    +
+

Description

+

The Classification directive sets the classification +level on the server. When this option is set, at least one of the +banner pages is forced to the classification level, and the +classification is placed on each page of output. The default is no +classification level. + +

+

DataDir

+
+

Examples

+
    +
    +DataDir /usr/share/cups
    +
    +
+

Description

+

The DataDir directive sets the directory to use for +data files. + +

+

DefaultCharset

+
+

Examples

+
    +
    +DefaultCharset utf-8
    +DefaultCharset iso-8859-1
    +DefaultCharset windows-1251
    +
    +
+

Description

+

The DefaultCharset directive sets the default character +set to use for client connections. The default character set is +utf-8 but is overridden by the character set for the language +specified by the client or the DefaultLanguage directive. + +

+

DefaultLanguage

+
+

Examples

+
    +
    +DefaultLanguage de
    +DefaultLanguage en
    +DefaultLanguage es
    +DefaultLanguage fr
    +DefaultLanguage it
    +
    +
+

Description

+

The DefaultLanguage directive specifies the default +language to use for client connections. Setting the default language +also sets the default character set if a language localization file +exists for it. The default language is "en" for English. + +

+

Deny

+
+

Examples

+
    +
    +Deny from All
    +Deny from None
    +Deny from *.domain.com
    +Deny from .domain.com
    +Deny from host.domain.com
    +Deny from nnn.*
    +Deny from nnn.nnn.*
    +Deny from nnn.nnn.nnn.*
    +Deny from nnn.nnn.nnn.nnn
    +Deny from nnn.nnn.nnn.nnn/mm
    +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
    +
+

Description

+

The Deny directive specifies a hostname, IP address, or +network that is allowed access to the server. Deny + directives are cummulative, so multiple Deny directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: +

+ + + + + + +
mmnetmask +mmnetmask
00.0.0.0 +8255.0.0.0
1128.0.0.0 +16255.255.0.0
2192.0.0.0 +24255.255.255.0
...... +32255.255.255.255
+
+

+

The Deny directive must appear inside a +Location directive. + +

+

DocumentRoot

+
+

Examples

+
    +
    +DocumentRoot /usr/share/doc/cups
    +DocumentRoot /foo/bar/doc/cups
    +
    +
+

Description

+

The DocumentRoot directive specifies the location of +web content for the HTTP server in CUPS. If an absolute path is not +specified then it is assumed to be relative to the +ServerRoot directory. The default directory is +/usr/share/doc/cups.

+

Documents are first looked up in a sub-directory for the primary +language requested by the client (e.g. /usr/share/doc/cups/fr/... +) and then directly under the DocumentRoot directory (e.g. +/usr/share/doc/cups/...), so it is possible to localize the web +content by providing subdirectories for each language needed. + +

+

Encryption

+
+

Examples

+
    +
    +Encryption Never
    +Encryption IfRequested
    +Encryption Required
    +Encryption Always
    +
    +
+

Description

+

The Encryption directive must appear instead a +Location section and specifies the encryption settings +for that location. The default setting is IfRequested for +all locations. + +

+

ErrorLog

+
+

Examples

+
    +
    +ErrorLog /var/log/cups/error_log
    +ErrorLog /var/log/cups/error_log-%s
    +ErrorLog syslog
    +
    +
+

Description

+

The ErrorLog directive sets the name of the error log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default error log file is /var/log/cups/error_log.

+

The server name can be included in the filename by using %s + in the name.

+

The special name "syslog" can be used to send the error information +to the system log instead of a plain file. + +

+

FilterLimit

+
+

Examples

+
    +
    +FilterLimit 0
    +FilterLimit 200
    +FilterLimit 1000
    +
    +
+

Description

+

The FilterLimit directive sets the maximum cost of all +running job filters. It can be used to limit the number of filter +programs that are run on a server to minimize disk, memory, and CPU +resource problems. A limit of 0 disables filter limiting.

+

An average print to a non-PostScript printer needs a filter limit of +about 200. A PostScript printer needs about half that (100). Setting +the limit below these thresholds will effectively limit the scheduler +to printing a single job at any time.

+

The default limit is 0. + +

+

FontPath

+
+

Examples

+
    +
    +FontPath /foo/bar/fonts
    +FontPath /usr/share/cups/fonts:/foo/bar/fonts
    +
    +
+

Description

+

The FontPath directive specifies the font path to use +when searching for fonts. The default font path is +/usr/share/cups/fonts. + +

+

Group

+
+

Examples

+
    +
    +Group sys
    +Group system
    +Group root
    +
    +
+

Description

+

The Group directive specifies the UNIX group that +filter and CGI programs run as. The default group is sys, +system, or root depending on the operating system. + +

+

HostNameLookups

+
+

Examples

+
    +
    +HostNameLookups On
    +HostNameLookups Off
    +HostNameLookups Double
    +
    +
+

Description

+

The HostNameLookups directive controls whether or not +CUPS looks up the hostname for connecting clients. The Double + setting causes CUPS to verify that the hostname resolved from the +address matches one of the addresses returned for that hostname. +Double lookups also prevent clients with unregistered addresses +from connecting to your server. The default is Off to +avoid the potential server performance problems with hostname lookups. +Set this option to On or Double only if +absolutely required. + +

+

ImplicitClasses

+
+

Examples

+
    +
    +ImplicitClasses On
    +ImplicitClasses Off
    +
    +
+

Description

+

The ImplicitClasses directive controls whether implicit +classes are created based upon the available network printers and +classes. The default setting is On but is automatically +turned Off if Browsing + is turned Off. + +

+

KeepAlive

+
+

Examples

+
    +
    +KeepAlive On
    +KeepAlive Off
    +
    +
+

Description

+

The KeepAlive directive controls whether or not to +support persistent HTTP connections. The default is On.

+

HTTP/1.1 clients automatically support persistent connections, while +HTTP/1.0 clients must specifically request them using the +Keep-Alive attribute in the Connection: field of +each request. + +

+

KeepAliveTimeout

+
+

Examples

+
    +
    +KeepAliveTimeout 60
    +KeepAliveTimeout 30
    +
    +
+

Description

+

The KeepAliveTimeout directive controls how long a +persistent HTTP connection will remain open after the last request. The +default is 60 seconds. + +

+

Limit

+
+

Examples

+
    +
    +<Limit GET POST>
    +...
    +</Limit>
    +
    +<Limit ALL>
    +...
    +</Limit>
    +
    +
+

Description

+

The Limit directive groups access control directives +for specific types of HTTP requests and must appear inside a +Location section. Access can be limited for individual +request types (DELETE, GET, HEAD +, OPTIONS, POST, PUT, and +TRACE) or for all request types (ALL). The request +type names are case-sensitive for compatibility with Apache. + +

+

LimitExcept

+
+

Examples

+
    +
    +<LimitExcept GET POST>
    +...
    +</LimitExcept>
    +
    +
+

Description

+

The LimitExcept directive groups access control +directives for specific types of HTTP requests and must appear inside a Location section. Unlike the +Limit directive, LimitExcept restricts +access for all requests except those listed on the +LimitExcept line. + +

+

LimitRequestBody

+
+

Examples

+
    +
    +LimitRequestBody 10485760
    +LimitRequestBody 10m
    +LimitRequestBody 0
    +
    +
+

Description

+

The LimitRequestBody directive controls the maximum +size of print files, IPP requests, and HTML form data in HTTP POST +requests. The default limit is 0 which disables the limit check.

+

Also see the identical MaxRequestSize + directive. + +

+

Listen

+
+

Examples

+
    +
    +Listen 127.0.0.1:631
    +Listen 192.0.2.1:631
    +
    +
+

Description

+

The Listen directive specifies a network address and +port to listen for connections. Multiple Listen directives +can be provided to listen on multiple addresses.

+

The Listen directive is similar to the +Port directive but allows you to restrict access to specific +interfaces or networks. + +

+

Location

+
+

Examples

+
    +
    +<Location />
    +...
    +</Location>
    +
    +<Location /admin>
    +...
    +</Location>
    +
    +<Location /printers/name>
    +...
    +</Location>
    +
    +
+

Description

+

The Location directive specifies access control and +authentication options for the specified HTTP resource or path. More +information can be found later in this chapter in +"Printing System Security". + +

+

LogLevel

+
+

Examples

+
    +
    +LogLevel none
    +LogLevel emerg
    +LogLevel alert
    +LogLevel crit
    +LogLevel error
    +LogLevel warn
    +LogLevel notice
    +LogLevel info
    +LogLevel debug
    +LogLevel debug2
    +
    +
+

Description

+

The LogLevel directive specifies the level of logging +for the ErrorLog file. The +following values are recognized (each level logs everything under the +preceding levels):

+
    +
  • none - Log nothing.
  • +
  • emerg - Log emergency conditions that prevent the + server from running.
  • +
  • alert - Log alerts that must be handled immediately.
  • +
  • crit - Log critical errors that don't prevent the +server from running.
  • +
  • error - Log general errors.
  • +
  • warn - Log errors and warnings.
  • +
  • notice - Log temporary error conditions.
  • +
  • info - Log all requests and state changes (default).
  • +
  • debug - Log basic debugging information.
  • +
  • debug2 - Log all debugging information.
  • +
+ + +

MaxClients

+
+

Examples

+
    +
    +MaxClients 100
    +MaxClients 1024
    +
    +
+

Description

+

The MaxClients directive controls the maximum number of +simultaneous clients that will be allowed by the server. The default is +100 clients. +

+ + +
NOTE: +

Since each print job requires a file descriptor for the status +pipe, the CUPS server internally limits the MaxClients + value to 1/3 of the available file descriptors to avoid possible +problems when printing large numbers of jobs.

+
+
+ + +

+

MaxJobs

+
+

Examples

+
    +
    +MaxJobs 100
    +MaxJobs 9999
    +MaxJobs 0
    +
    +
+

Description

+

The MaxJobs directive controls the maximum number of +jobs that are kept in memory. Once the number of jobs reaches the +limit, the oldest completed job is automatically purged from the system +to make room for the new one. If all of the known jobs are still +pending or active then the new job will be rejected.

+

Setting the maximum to 0 disables this functionality. The default +setting is 0. + +

+

MaxJobsPerPrinter

+
+

Examples

+
    +
    +MaxJobsPerPrinter 100
    +MaxJobsPerPrinter 9999
    +MaxJobsPerPrinter 0
    +
    +
+

Description

+

The MaxJobsPerPrinter directive controls the maximum +number of active jobs that are allowed for each printer or class. Once +a printer or class reaches the limit, new jobs will be rejected until +one of the active jobs is completed, stopped, aborted, or cancelled.

+

Setting the maximum to 0 disables this functionality. The default +setting is 0. + +

+

MaxJobsPerUser

+
+

Examples

+
    +
    +MaxJobsPerUser 100
    +MaxJobsPerUser 9999
    +MaxJobsPerUser 0
    +
    +
+

Description

+

The MaxJobsPerUser directive controls the maximum +number of active jobs that are allowed for each user. Once a user +reaches the limit, new jobs will be rejected until one of the active +jobs is completed, stopped, aborted, or cancelled.

+

Setting the maximum to 0 disables this functionality. The default +setting is 0. + +

+

MaxLogSize

+
+

Examples

+
    +
    +MaxLogSize 1048576
    +MaxLogSize 1m
    +MaxLogSize 0
    +
    +
+

Description

+

The MaxLogSize directive controls the maximum size of +each log file. Once a log file reaches or exceeds the maximum size it +is closed and renamed to filename.O. This allows you to +rotate the logs automatically. The default size is 1048576 bytes (1MB).

+

Setting the maximum size to 0 disables log rotation. + +

+

MaxRequestSize

+
+

Examples

+
    +
    +MaxRequestSize 10485760
    +MaxRequestSize 10m
    +MaxRequestSize 0
    +
    +
+

Description

+

The MaxRequestSize directive controls the maximum size +of print files, IPP requests, and HTML form data in HTTP POST requests. +The default limit is 0 which disables the limit check.

+

Also see the identical +LimitRequestBody directive. + +

+

Order

+
+

Examples

+
    +
    +Order Allow,Deny
    +Order Deny,Allow
    +
    +
+

Description

+

The Order directive defines the default access control. +The following values are supported:

+
    +
  • Allow,Deny - Allow requests from all systems except + for those listed in a Deny directive.
  • +
  • Deny,Allow - Allow requests only from those listed in +an Allow directive.
  • +
+

The Order directive must appear inside a +Location directive. + +

+

PageLog

+
+

Examples

+
    +
    +PageLog /var/log/cups/page_log
    +PageLog /var/log/cups/page_log-%s
    +PageLog syslog
    +
    +
+

Description

+

The PageLog directive sets the name of the page log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default page log file is /var/log/cups/page_log.

+

The server name can be included in the filename by using %s + in the name.

+

The special name "syslog" can be used to send the page information +to the system log instead of a plain file. + +

+

Port

+
+

Examples

+
    +
    +Port 631
    +Port 80
    +
    +
+

Description

+

The Port directive specifies a port to listen on. +Multiple Port lines can be specified to listen on multiple +ports. The default port is 631. + +

+

PreserveJobHistory

+
+

Examples

+
    +
    +PreserveJobHistory On
    +PreserveJobHistory Off
    +
    +
+

Description

+

The PreserveJobHistory directive controls whether the +history of completed, cancelled, or aborted print jobs is stored on +disk.

+

A value of On (the default) preserves job information +until the administrator purges it with the cancel command.

+

A value of Off removes the job information as soon as +each job is completed, cancelled, or aborted. + +

+

PreserveJobFiles

+
+

Examples

+
    +
    +PreserveJobFiles On
    +PreserveJobFiles Off
    +
    +
+

Description

+

The PreserveJobFiles directive controls whether the +document files of completed, cancelled, or aborted print jobs are +stored on disk.

+

A value of On preserves job files until the +administrator purges them with the cancel command. Jobs +can be restarted (and reprinted) as desired until they are purged.

+

A value of Off (the default) removes the job files as +soon as each job is completed, cancelled, or aborted. + +

+

Printcap

+
+

Examples

+
    +
    +Printcap
    +Printcap /etc/printcap
    +Printcap /etc/printers.conf
    +
    +
+

Description

+

The Printcap directive controls whether or not a +printcap file is automatically generated and updated with a list of +available printers. If specified with no value, then no printcap file +will be generated. The default is to generate a file named +/etc/printcap.

+

When a filename is specified (e.g. /etc/printcap), the +printcap file is written whenever a printer is added or removed. The +printcap file can then be used by applications that are hardcoded to +look at the printcap file for the available printers. + +

+

PrintcapFormat

+
+

Examples

+
    +
    +PrintcapFormat BSD
    +PrintcapFormat Solaris
    +
    +
+

Description

+

The PrintcapFormat directive controls the output format +of the printcap file. The default is to generate a BSD printcap file. + +

+

RemoteRoot

+
+

Examples

+
    +
    +RemoteRoot remroot
    +RemoteRoot root
    +
    +
+

Description

+

The RemoteRoot directive sets the username for +unauthenticated root requests from remote hosts. The default username +is remroot. Setting RemoteRoot to root + effectively disables this security mechanism. + +

+

RequestRoot

+
+

Examples

+
    +
    +RequestRoot /var/spool/cups
    +RequestRoot /foo/bar/spool/cups
    +
    +
+

Description

+

The RequestRoot directive sets the directory for +incoming IPP requests and HTML forms. If an absolute path is not +provided then it is assumed to be relative to the +ServerRoot directory. The default request directory is +/var/spool/cups. + +

+

RIPCache

+
+

Examples

+
    +
    +RIPCache 8m
    +RIPCache 1g
    +RIPCache 2048k
    +
    +
+

Description

+

The RIPCache directive sets the size of the memory +cache used by Raster Image Processor ("RIP") filters such as +imagetoraster and pstoraster. The size can be +suffixed with a "k" for kilobytes, "m" for megabytes, or "g" for +gigabytes. The default cache size is "8m", or 8 megabytes. + +

+

RunAsUser

+
+

Examples

+
    +
    +RunAsUser Yes
    +RunAsUser No
    +
    +
+

Description

+

The RunAsUser directive controls whether the scheduler +runs as the unpriviledged user account (usually lp). The +default is No which leaves the scheduler running as the +root user.

+

Note: Running as a non-priviledged user may prevent LPD and +locally connected printers from working due to permission problems. The +lpd backend will automatically use a non-priviledged mode that +is not 100% compliant with RFC 1179. The parallel, +serial, and usb backends will need write access to +the corresponding device files. + +

+

ServerAdmin

+
+

Examples

+
    +
    +ServerAdmin user@host
    +ServerAdmin root@foo.bar.com
    +
    +
+

Description

+

The ServerAdmin directive identifies the email address +for the administrator on the system. By default the administrator email +address is root@server, where server is the +server name. + +

+

ServerBin

+
+

Examples

+
    +
    +ServerBin /usr/lib/cups
    +ServerBin /foo/bar/lib/cups
    +
    +
+

Description

+

The ServerBin directive sets the directory for +server-run executables. If an absolute path is not provided then it is +assumed to be relative to the ServerRoot + directory. The default executable directory is /usr/lib/cups + or /usr/lib32/cups (IRIX 6.5). + +

+

ServerCertificate

+
+

Examples

+
    +
    +ServerCertificate /etc/cups/ssl/server.crt
    +
    +
+

Description

+

The ServerCertificate directive specifies the location +of the SSL certificate file used by the server when negotiating +encrypted connections. The certificate must not be encrypted (password +protected) since the scheduler normally runs in the background and will +be unable to ask for a password. The default certificate file is +/etc/cups/ssl/server.crt. + +

+

ServerKey

+
+

Examples

+
    +
    +ServerKey /etc/cups/ssl/server.key
    +
    +
+

Description

+

The ServerKey directive specifies the location of the +SSL private key file used by the server when negotiating encrypted +connections. The default key file is /etc/cups/ssl/server.crt +. + +

+

ServerName

+
+

Examples

+
    +
    +ServerName foo.domain.com
    +ServerName myserver.domain.com
    +
    +
+

Description

+

The ServerName directive specifies the hostname that is +reported to clients. By default the server name is the hostname. + +

+

ServerRoot

+
+

Examples

+
    +
    +ServerRoot /etc/cups
    +ServerRoot /foo/bar/cups
    +
    +
+

Description

+

The ServerRoot directive specifies the absolute path to +the server configuration and state files. It is also used to resolve +relative paths in the cupsd.conf file. The default server +directory is /etc/cups. + +

+

SSLListen

+
+

Examples

+
    +
    +SSLListen 127.0.0.1:443
    +SSLListen 192.0.2.1:443
    +
    +
+

Description

+

The SSLListen directive specifies a network address and +port to listen for secure connections. Multiple SSLListen + directives can be provided to listen on multiple addresses.

+

The SSLListen directive is similar to the +SSLPort directive but allows you to restrict access to +specific interfaces or networks. + +

+

SSLPort

+
+

Examples

+
    +
    +SSLPort 443
    +
    +
+

Description

+

The SSLPort directive specifies a port to listen on for +secure connections. Multiple SSLPort lines can be +specified to listen on multiple ports. + +

+

SystemGroup

+
+

Examples

+
    +
    +SystemGroup sys
    +SystemGroup system
    +SystemGroup root
    +
    +
+

Description

+

The SystemGroup directive specifies the system +administration group for System authentication. More +information can be found later in this chapter in +"Printing System Security". + +

+

TempDir

+
+

Examples

+
    +
    +TempDir /var/tmp
    +TempDir /foo/bar/tmp
    +
    +
+

Description

+

The TempDir directive specifies an absolute path for +the directory to use for temporary files. The default directory is +/var/tmp.

+

Temporary directories must be world-writable and should have the +"sticky" permission bit enabled so that other users cannot delete +filter temporary files. The following commands will create an +appropriate temporary directory called /foo/bar/tmp:

+
    +
    +mkdir /foo/bar/tmp ENTER
    +chmod a+rwxt /foo/bar/tmp ENTER
    +
    +
+ + +

Timeout

+
+

Examples

+
    +
    +Timeout 300
    +Timeout 90
    +
    +
+

Description

+

The Timeout directive controls the amount of time to +wait before an active HTTP or IPP request times out. The default +timeout is 300 seconds. + +

+

User

+
+

Examples

+
    +
    +User lp
    +User guest
    +
    +
+

Description

+

The User directive specifies the UNIX user that filter +and CGI programs run as. The default user is lp. + +

+

Printing System Security

+

CUPS provides support for address, certificate, and password (Basic +and Digest) based authentication and access control. Certificate and +password authentication provide ways to limit access to individual +people or groups.

+

Address based access control allows you to limit access to specific +systems, networks, or domains. While this does not provide +authentication, it does allow you to limit the potential users of your +system efficiently.

+

CUPS maintains a list of locations that have access control and/or +authentication enabled. Locations are specified using the +Location directive:

+ +

Locations generally follow the directory structure of the +DocumentRoot directory, however CUPS does have several +virtual locations for administration, classes, jobs, and printers: +

+ + + + + + + + + + + + +
LocationDescription
/adminThe path for all administration operations.
/classesThe path for all classes.
/classes/nameThe resource for class name.
/jobsThe path for all jobs.
/jobs/idThe resource for job id.
/printersThe path for all printers.
/printers/nameThe path for printer name.
/printers/name.ppdThe PPD file path for printer +name.
+
+

+

Authentication Using Certificates

+

CUPS supports a local certificate-based authentication scheme that +can be used in place of Basic or Digest + authentication by clients connecting through the localhost + interface. Certificate authentication is not supported or allowed from +clients on any other interface.

+

Certificates are 128-bit random numbers that refer to an internal +authentication record in the server. A client connecting via the +localhost interface sends a request with an authorization header +of:

+
    +
    +Authorization: Local 0123456789ABCDEF0123456789ABCDEF
    +
    +
+

The server then looks up the local certificate and authenticates +using the username associated with it.

+

Certificates are generated by the server automatically and stored in +the /etc/cups/certs directory using the process ID of the +CGI program started by the server. Certificate files are only readable +by the User and +Group defined in the cupsd.conf file. When the +CGI program ends the certificate is removed and invalidated +automatically.

+

The special file /etc/cups/certs/0 defines the root +certificate which can be used by any client running as the +super-user or another user that is part of the group defined by the +SystemGroup directive. The root certificate is +automatically regenerated every 5 minutes.

+

Using Basic Authentication

+

Basic authentication uses UNIX users and passwords to authenticate +access to resources such as printers and classes, and to limit access +to administrative functions. +

+ + +
NOTE: +

Basic authentication sends the username and password Base64 encoded +from the client to the server, so it offers no protection against +eavesdropping. This means that a malicious user can monitor network +packets and discover valid users and passwords that could result in a +serious compromise in network security. Use Basic authentication with +extreme care.

+
+
+

+

The CUPS implementation of Basic authentication does not allow +access through user accounts without a password. If you try to +authenticate using an account without a password, your access will be +immediately blocked.

+

Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked. +

+ + +
NOTE: +

The root user is considered by CUPS to be a member of every group.

+
+
+ + +

+

Use the AuthType directive to enable Basic +authentication:

+
    +
    +AuthType Basic
    +
    +
+ + +

Using Digest Authentication

+

Digest authentication uses users and passwords defined in the +/etc/cups/passwd.md5 file to authenticate access to resources +such as printers and classes, and to limit access to administrative +functions. +

+ + +
NOTE: +

Unlike Basic authentication, Digest passes the MD5 sum (basically a +complicated checksum) of the username and password instead of the +strings themselves. Also, Digest authentication does not use the UNIX +password file, so if an attacker does discover the original password +it is less likely to result in a serious security problem so long as +you use a different UNIX password than the corresponding Digest +password.

+

The current CUPS implementation of Digest authentication uses the +client's hostname or IP address for the "nonce" value. The nonce value +is an additional string added to the username and password to make +guessing the password more difficult. The server checks that the nonce +value matches the client's hostname or address and rejects the MD5 sum +if it doesn't. Future versions of CUPS will support Digest "session" +authentication which adds the request data to the MD5 sum, providing +even better authentication and security.

+

Digest authentication does not guarantee that an attacker cannot +gain unauthorized access, but it is safer than Basic authentication +and should be used in place of Basic authentication whenever possible. +Support for Digest authentication in web browsers is not yet +universally available.

+
+
+ + +

+

The lppasswd(1) command is used to add, change, or +remove accounts from the passwd.md5 file. To add a user to +the default system group, type:

+
    +
    +lppasswd -a user ENTER
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
    +
+ + +

Once added, a user can change his/her password by typing:

+
    +
    +lppasswd ENTER
    +Old password: (password) ENTER [password is not echoed]
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
    +
+ + +

To remove a user from the password file, type:

+
    +
    +lppasswd -x user ENTER
    +
    +
+

Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked. +

+ + +
NOTE: +

The root user is considered by CUPS to be a member of every group.

+
+
+

+

Use the AuthType directive to enable Digest +authentication:

+
    +
    +AuthType Digest
    +
    +
+

System and Group Authentication

+

The AuthClass directive +controls the level of authentication to perform. System + and Group authentication extend the normal user-based +authentication to require membership in a UNIX group. For System + authentication each user must belong to the sys, +system, or root group; the actual group depends on +the operating system.

+

For Group authentication each user must belong to the +group named by the AuthGroupName + directive:

+
    +
    +<Location /path>
    +AuthType Digest
    +AuthClass Group
    +AuthGroupName mygroup
    +</Location>
    +
    +
+

The named group must be a valid UNIX user group, usually defined in +the /etc/group or /etc/netgroup files. +Additionally, when using Digest authentication you need to create user +accounts with the named group:

+
    +
    +lppasswd -g mygroup -a user ENTER
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
    +
+ + +

Printer Accounting

+

ESP Print Pro maintains a log of all accesses, errors, and pages +that are printed. The log files are normally stored in the +/var/log/cups directory. You can change this by editing the +/etc/cups/cupsd.conf configuration file.

+

The access_log File

+

The access_log file lists each HTTP resource that is +accessed by a web browser or CUPS/IPP client. Each line is in the +so-called "Common Log Format" used by many web servers and web +reporting tools:

+
    +
    +host group user date-time \"method resource version\" status bytes
    +
    +127.0.0.1 - - [20/May/1999:19:20:29 +0000] "POST /admin/ HTTP/1.1" 401 0
    +127.0.0.1 - mike [20/May/1999:19:20:31 +0000] "POST /admin/ HTTP/1.1" 200 0
    +
    +
+

The host field will normally only be an IP address unless you +have enabled the HostNameLookups + directive in the cupsd.conf file.

+

The group field always contains "-" in CUPS.

+

The user field is the authenticated username of the +requesting user. If no username and password is supplied for the +request then this field contains "-".

+

The date-time field is the date and time of the request in +local time and is in the format:

+
    +
    +[DD/MON/YYYY:HH:MM:SS +ZZZZ]
    +
    +
+

where ZZZZ is the timezone offset in hours and minutes from +Greenwich Mean Time (a.k.a. GMT a.k.a. ZULU.)

+

The method field is the HTTP method used ("GET", "PUT", +"POST", etc.)

+

The resource field is the filename of the requested resource.

+

The version field is the HTTP specification version used by +the client. For CUPS clients this will always be "HTTP/1.1".

+

The status field contains the HTTP result status of the +request. Usually it is "200", but other HTTP status codes are possible. +For example, 401 is the "unauthorized access" status in the example +above.

+

The bytes field contains the number of bytes in the request. +For POST requests the bytes field contains the number of bytes +that was received from the client.

+

The error_log File

+

The error_log file lists messages from the scheduler +(errors, warnings, etc.):

+
    +
    +level date-time message
    +
    +I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.
    +
    +
+

The level field contains the type of message:

+
    +
  • E - An error occurred.
  • +
  • W - The server was unable to perform some action.
  • +
  • I - Informational message.
  • +
  • D - Debugging message.
  • +
+

The date-time field contains the date and time of when the +page started printing. The format of this field is identical to the +data-time field in the access_log file.

+

The message fields contains a free-form textual message.

+

The page_log File

+

The page_log file lists each page that is sent to a +printer. Each line contains the following information:

+
    +
    +printer user job-id date-time page-number num-copies job-billing
    +
    +DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0 acme-123
    +
    +
+

The printer field contains the name of the printer that +printed the page. If you send a job to a printer class, this field will +contain the name of the printer that was assigned the job.

+

The user field contains the name of the user (the IPP +requesting-user-name attribute) that submitted this file for +printing.

+

The job-id field contains the job number of the page being +printed. Job numbers are reset to 1 whenever the CUPS server is +started, so don't depend on this number being unique!

+

The date-time field contains the date and time of when the +page started printing. The format of this field is identical to the +data-time field in the access_log file.

+

The page-number and num-pages fields contain the page +number and number of copies being printed of that page. For printer +that can not produce copies on their own, the num-pages field +will always be 1.

+

The job-billing field contains a copy of the job-billing + attribute provided with the IPP create-job or +print-job requests or "-" if none was provided. + +

+

File Typing and Filtering

+

CUPS provides a MIME-based file typing and filtering mechanism to +convert files to a printable format for each printer. On startup the +CUPS server reads MIME database files from the /etc/cups + directory (or a directory specified by the +ServerRoot directive) to build a file type and conversion +database in memory. These database files are plain ASCII text and can +be edited with your favorite text editor.

+

The mime.types and mime.convs files define the +standard file types and filters that are available on the system.

+

mime.types

+

The mime.types file defines the known file types. Each +line of the file starts with the MIME type and may be followed by one +or more file type recognition rules. For example, the text/html + file type is defined as:

+
    +
    +text/html       html htm \
    +                printable(0,1024) + \
    +                (string(0,"<HTML>") string(0,"<!DOCTYPE"))
    +
    +
+

The first two rules say that any file with an extension of .html + or .htm is a HTML file. The third rule says that any file +whose first 1024 characters are printable text and starts with the +strings <HTML> or <!DOCTYPE is a HTML file as +well.

+

The first two rules deal solely with the name of the file being +typed. This is useful when the original filename is known, however for +print files the server doesn't have a filename to work with. The third +rule takes care of this possibility and automatically figures out the +file type based upon the contents of the file instead.

+

The available tests are:

+
    +
  • ( expr ) - Parenthesis for expression grouping
  • +
  • + - Logical AND
  • +
  • , or whitespace - Logical OR
  • +
  • ! - Logical NOT
  • +
  • match("pattern") - Pattern match on filename
  • +
  • extension - Pattern match on "*.extension"
  • +
  • ascii(offset,length) - True if bytes are valid + printable ASCII (CR, NL, TAB, BS, 32-126)
  • +
  • printable(offset,length) - True if bytes are + printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254)
  • +
  • string(offset,"string") - True if bytes are identical +to string
  • +
  • contains(offset,range,"string") - True if the range +of bytes contains the string
  • +
  • char(offset,value) - True if byte is identical
  • +
  • short(offset,value) - True if 16-bit integer is +identical (network or "big-endian" byte order)
  • +
  • int(offset,value) - True if 32-bit integer is + identical (network or "big-endian" byte order)
  • +
  • locale("string") - True if current locale matches +string
  • +
+

All numeric values can be in decimal (123), octal (0123), or +hexadecimal (0x123) as desired. + +

+

Strings can be in quotes, all by themselves, as a string of +hexadecimal values, or some combination:

+
    +
    +"string"
    +'string'
    +string
    +<737472696e67>
    +<7374>ring
    +
    +
+

As shown in the text/html example, rules can continue +on multiple lines using the backslash (\) character. A more complex +example is the image/jpeg rules:

+
    +
    +image/jpeg      jpeg jpg jpe string(0,<FFD8FF>) &&\
    +                (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
    +                 char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
    +                 char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
    +                 char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
    +
    +
+

This rule states that any file with an extension of .jpeg +, .jpg, or .jpe is a JPEG file. In addition, any +file starting with the hexadecimal string <FFD8FF> (JPEG +Start-Of-Image) followed by a character between and including 0xe0 + and 0xef (JPEG APPn markers) is also a JPEG file.

+

mime.convs

+

The mime.convs file defines all of the filter programs +that are known to the system. Each line consists of:

+
    +
    +source destination cost program
    +
    +text/plain application/postscript 50 texttops
    +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster
    +image/* application/vnd.cups-postscript 50 imagetops
    +image/* application/vnd.cups-raster 50 imagetoraster
    +
    +
+

The source field is a MIME type, optionally using a wildcard +for the super-type or sub-type (e.g. "text/plain", "image/*", +"*/postscript").

+

The destination field is a MIME type defined in the +mime.types file.

+

The cost field defines a relative cost for the filtering +operation from 1 to 100. The cost is used to choose between two +different sets of filters when converting a file. For example, to +convert from image/jpeg to +application/vnd.cups-raster, you could use the imagetops + and pstoraster filters for a total cost of 100, or the +imagetoraster filter for a total cost of 50.

+

The program field defines the filter program to run; the +special program "-" can be used to make two file types equivalent. The +program must accept the standard filter arguments and environment +variables described in the CUPS Interface Design Description and CUPS +Software Programmers Manual:

+
    +
    +program job user title options [filename]
    +
    +
+

If specified, the filename argument defines a file to read +when filtering, otherwise the filter must read from the standard input. +All filtered output must go to the standard output. + +

+

Adding Filetypes and Filters

+

Adding a new file type or filter is fairly straight-forward. Rather +than adding the new type and filter to the mime.types and +mime.convs files which are overwritten when you upgrade to a new +version of CUPS, you simple need to create new files with .types + and .convs extensions in the /etc/cups + directory. We recommend that you use the product or format name, e.g.:

+
    +
    +myproduct.types
    +myproduct.convs
    +
    +
+

If you are providing a filter for a common file format or printer, +add the company or author name:

+
    +
    +acme-msword.types
    +acme.msword.convs
    +
    +
+

This will help to prevent name collisions if you install many +different file types and filters.

+

Once you choose the names for these files, create them using your +favorite text editor as described earlier in this chapter. Once you +have created the files, restart the cupsd process as +described earlier in "Restarting the CUPS Server" +.

+

Printer Drivers and PPD Files

+

Most CUPS printer drivers utilize one or more printer-specific +filters and a PPD file for each printer model. Printer driver filters +are registered via the PPD file using cupsFilter + attributes:

+
    +
    +*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
    +
    +
+

The filter is specified using the source file type only; the +destination file type is assumed to be printer/name - +suitable for sending to the printer.

+

Writing Your Own Filter or Printer Driver

+

CUPS supports an unlimited number of file formats and filters, and +can handle any printer. If you'd like to write a filter or printer +driver for your favorite file format or printer, consult the CUPS +Software Programmers Manual for step-by-step instructions.

+

7 - Printing with Other +Systems

+

This chapter describes how to print from client systems that use the +LPD, Mac OS, or Windows printing protocols.

+

The Basics

+

CUPS is based on the IPP protocol, so any system that supports IPP +can send jobs to and receive jobs from CUPS automatically. However, not +all systems support IPP yet. This chapter will show you how to connect +these systems to your CUPS server, either to accept jobs from your +server for printing, or to send jobs to your server.

+

Printing from LPD Clients

+

CUPS supports limited functionality for LPD-based clients. With LPD +you can print files to specific printers, list the queue status, and so +forth. However, the automatic client configuration and printer options +are not supported by the LPD protocol, so you must manually configure +each client for the printers it needs to access.

+

The cups-lpd(8) program provides support for LPD +clients. To enable LPD support on your server, edit the +/etc/inetd.conf file and add a line reading:

+
    +
    +printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
    +
    +
+

The path to the cups-lpd may vary depending on your +installation.

+

Once you have added this line, send the inetd(8) + process a HUP signal or reboot the system:

+
    +
    +killall -HUP inetd ENTER [IRIX and some versions of Linux]
    +kill -HUP pid ENTER [Others]
    +reboot ENTER [For all systems if the HUP signal fails]
    +
    +
+

Printing to LPD Servers

+

CUPS provides the lpd backend for printing to LPD-based +servers and printers. Use a device URI of lpd://server/name + to print to a printer on an LPD server, where server is +the hostname or IP address of the server and name is the +queue name.

+

Microsoft Windows NT provides an LPD service under the name "TCP/IP +Printing Services". To enable LPD printing on NT, open the "Services" +control panel, select the "TCP/IP Printing Services" service, and click +on the "Start" button. Any shared printer will then be available via +the LPD protocol.

+

Printing from Mac OS Clients

+

CUPS does not provide Mac OS support directly. However, there are +several free and commercial software packages that do.

+

Columbia Appletalk Package (CAP)

+

Because the CAP LaserWriter server (lwsrv(8)) does not +support specification of PPD files, we do not recommend that you use +CAP with CUPS. However, you can run the lpsrv program for +limited printing with the command:

+
    +
    +lwsrv -n "Name" -p printer -a /usr/lib/adicts -f /usr/lib/LW+Fonts
    +
    +
+

where Name is the name you want to use when sharing the +printer, and printer is the name of the CUPS print queue. + +

+

XINET KA/Spool

+

To use your system as a print server for Mac OS clients, configure +each printer using a papserver(8) in the +/usr/adm/appletalk/services file, specifying the corresponding +PPD file in the /etc/cups/ppd directory for each printer. + For a printer named MyPrinter the entry would look like:

+
    +
    +/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
    +"Printer Description" MyPrinter
    +
    +
+
+ + +
NOTE: +

Enter the text above on a single line without the backslash (\) + character.

+
+
+

NetATalk

+

To use your system as a print server for Mac OS clients, configure +each printer in the papd.conf file, specifying the +corresponding PPD file in the /etc/cups/ppd directory for +each printer. For a printer named MyPrinter the entry +would look like:

+
    +
    +Printer Description:MyPrinter@MyServer:\
    +        :pr=|/usr/bin/lp -d MyPrinter:\
    +        :op=daemon:\
    +        :pd=/etc/cups/ppd/MyPrinter.ppd:
    +
    +
+ + +

Printing to Mac OS Servers

+

CUPS currently does not provide a backend to communicate with a Mac +OS server. However, you can write and install a short shell script in +the /usr/lib/cups/backend directory that sends a print file +using the appropriate command. The following is a short script that +will run the papif command provided with CAP.

+

After copying this script to /usr/lib/cups/backend/cap, +specify a device URI of cap://server/printer to use this +backend with a print queue. + +

+
    +
    +"/usr/lib/cups/backend/cap"
    +#!/bin/sh
    +#
    +# Usage: cap job user title copies options [filename]
    +#
    +
    +# No arguments means show available devices...
    +
    +if test ${#argv} = 0; then
    +	echo "network cap \"Unknown\" \"Mac OS Printer via CAP\""
    +	exit 0
    +fi
    +
    +# Collect arguments...
    +
    +user=$2
    +copies=$4
    +
    +if test ${#argv} = 5; then
    +	# Get print file from stdin; copies have already been handled...
    +	file=/var/tmp/$$.prn
    +	copies=1
    +	cat > $file
    +else
    +	# Print file is on command-line...
    +	file=$6
    +fi
    +
    +# Create a dummy cap.printers file for this printer based
    +# upon a device URI of "cap://server/printer"...
    +
    +echo $PRINTER/$DEVICE_URI | \
    +	awk -F/ '{print $1 "=" $5 ":LaserWriter@" $4}' > /var/tmp/$$.cap
    +
    +CAPPRINTERS=/var/tmp/$$.cap; export CAPPRINTERS
    +
    +# Send the file to the printer, once for each copy. This assumes that you
    +# have properly initialized the cap.printers file...
    +
    +while [ $copies -gt 0 ]; do
    +	papif -n $user < $file
    +
    +        copies=`expr $copies - 1`
    +done
    +
    +# Remove any temporary files...
    +if test ${#argv} = 5; then
    +	/bin/rm -f $file
    +fi
    +
    +/bin/rm -f /var/tmp/$$.cap
    +
    +exit 0
    +
    +
+ + +

Printing from Windows Clients

+

While CUPS does not provide Windows support directly, the free SAMBA +software package does. SAMBA version 2.0.6 is the first release of +SAMBA that supports CUPS. You can download SAMBA from:

+ +

To configure SAMBA for CUPS, edit the smb.conf file and +replace the existing printing commands and options with the line:

+
    +
    +printing = cups
    +
    +
+

That's all there is to it! Remote users will now be able to browse +and print to printers on your system.

+

Printing to Windows Servers

+

CUPS can print to Windows servers in one of two ways. The first way +uses the LPD protocol on the CUPS system and the "TCP/IP Printing +Services" on the Windows system. You can find out more about this +configuration in the LPD section earlier in this +chapter.

+

The second way is through the Microsoft Server Message Block ("SMB") +protocol. Support for this protocol is provided with the free SAMBA +software package. You can download SAMBA from:

+ +

To configure CUPS for SAMBA, run the following command:

+
    +
    +ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER
    +
    +
+

The smbspool(1) program is provided with SAMBA starting +with SAMBA 2.0.6. Once you have made the link you can configure your +printers with one of the following device URIs:

+
    +
    +smb://workgroup/server/sharename
    +smb://server/sharename
    +smb://user:pass@workgroup/server/sharename
    +smb://user:pass@server/sharename
    +
    +
+

The workgroup name need only be specified if your +system is using a different workgroup. The user:pass + strings are required when printing to Windows NT servers or to shares +with passwords enabled under Windows 95 and 98.

+

A - Software License Agreement

+

Common UNIX Printing System License +Agreement

+

Copyright 1997-2001 by Easy Software Products +
44141 AIRPORT VIEW DR STE 204 +
HOLLYWOOD, MARYLAND 20636-3111 USA +
+
Voice: +1.301.373.9600 +
Email: cups-info@cups.org +
WWW: http://www.cups.org

+

Introduction

+

The Common UNIX Printing SystemTM, ("CUPSTM"), +is provided under the GNU General Public License ("GPL") and GNU +Library General Public License ("LGPL"), Version 2. A copy of these +licenses follow this introduction.

+

The GNU LGPL applies to the CUPS API library, located in the "cups" +subdirectory of the CUPS source distribution and in the +"/usr/include/cups" directory and "libcups.a", "libcups.sl", or +"libcups.so" files in the binary distributions.

+

The GNU GPL applies to the remainder of the CUPS distribution, +including the "pstoraster" filter which is based upon GNU Ghostscript +5.50 and the "pdftops" filter which is based upon Xpdf 0.90.

+

For those not familiar with the GNU GPL, the license basically +allows you to:

+
    +
  • Use the CUPS software at no charge.
  • +
  • Distribute verbatim copies of the software in source or binary +form.
  • +
  • Sell verbatim copies of the software for a media fee, or sell +support for the software.
  • +
  • Distribute or sell printer drivers and filters that use CUPS so +long as source code is made available under the GPL.
  • +
+

What this license does not allow you to do is make changes or +add features to CUPS and then sell a binary distribution without source +code. You must provide source for any new drivers, changes, or +additions to the software, and all code must be provided under the GPL +or LGPL as appropriate.

+

The GNU LGPL relaxes the "link-to" restriction, allowing you to +develop applications that use the CUPS API library under other licenses +and/or conditions as appropriate for your application.

+

Trademarks

+

Easy Software Products has trademarked the Common UNIX Printing +System, CUPS, and CUPS logo. These names and logos may be used freely +in any direct port or binary distribution of CUPS. To use them in +derivative products, please contract Easy Software Products for written +permission. Our intention is to protect the value of these trademarks +and ensure that any derivative product meets the same high-quality +standards as the original.

+

Binary Distribution Rights

+

Easy Software Products also sells rights to the CUPS source code +under a binary distribution license for vendors that are unable to +release source code for their drivers, additions, and modifications to +CUPS under the GNU GPL and LGPL. For information please contact us at +the address shown above.

+

The Common UNIX Printing System provides a "pstoraster" filter that +utilizes the GNU GhostScript 5.50 core to convert PostScript files into +a stream of raster images. For binary distribution licensing of this +software, please contact:

Miles Jones +
Director of Marketing +
Artifex Software Inc. +
454 Las Gallinas Ave., Suite 108 +
San Rafael, CA 94903 USA +
Voice: +1.415.492.9861 +
Fax: +1.415.492.9862 +
EMail: info@arsoft.com
+

+

The "pdftops" filter is based on the Xpdf 0.90 software. For binary +distribution licensing of this software, please contact:

+ Derek B. Noonburg +
Email: derekn@foolabs.com +
WWW: +http://www.foolabs.com/xpdf/

+

Support

+

Easy Software Products sells software support for CUPS as well as a +commercial printing product based on CUPS called ESP Print Pro. You can +find out more at our web site:

+ + + +

GNU GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not allowed.
+
+
+
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it.

+

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights.

+

We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the software.

+

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, +so that any problems introduced by others will not reflect on the +original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all.

+

The precise terms and conditions for copying, distribution and +modification follow.

+

GNU GENERAL PUBLIC LICENSE +
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+
    +
  1. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you".
  2. +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does.

    +
  3. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the +Program.
  4. +

    You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

    +
  5. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: +
      +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change.
    2. +
    3. You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License.
    4. +
    5. if the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the most ordinary way, to print or display an announcement including +an appropriate copyright notice and a notice that there is no warranty +(or else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling the user +how to view a copy of this License. (Exception: if the Program itself +is interactive but does not normally print such an announcement, your +work based on the Program is not required to print an announcement.)
    6. +
    +
  6. +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

    +

    Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Program.

    +

    In addition, mere aggregation of another work not based on the +Program with the Program (or with a work based on the Program) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

    +
  7. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +
      +
    1. Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or,
    2. +
    3. Accompany it with a written offer, valid for at least three years, +to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or,
    4. +
    5. Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in accord +with Subsection b above.)
    6. +
    +
  8. +

    The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that +is normally distributed (in either source or binary form) with the +major components (compiler, kernel, and so on) of the operating system +on which the executable runs, unless that component itself accompanies +the executable.

    +

    If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent access +to copy the source code from the same place counts as distribution of +the source code, even though third parties are not compelled to copy +the source along with the object code.

    +
  9. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such parties +remain in full compliance.
  10. +
  11. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying the +Program or works based on it.
  12. +
  13. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License.
  14. +
  15. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program.
  16. +

    If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply and the section as a whole is intended to apply in +other circumstances.

    +

    It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.

    +

    This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

    +
  17. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License.
  18. +
  19. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns.
  20. +

    Each version is given a distinguishing version number. If the +Program specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation.

    +
  21. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally.
  22. +
+

NO WARRANTY

+
    +
  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS +WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  2. +
  3. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.
  4. +
+

END OF TERMS AND CONDITIONS

+ + +

GNU LIBRARY GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright (C) 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users.

+

This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it.

+

For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights.

+

Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library.

+

Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all.

+

Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License, which was designed for utility +programs. This license, the GNU Library General Public License, +applies to certain designated libraries. This license is quite +different from the ordinary one; be sure to read it in full, and don't +assume that anything in it is the same as in the ordinary license.

+

The reason we have a separate public license for some libraries is +that they blur the distinction we usually make between modifying or +adding to a program and simply using it. Linking a program with a +library, without changing the library, is in some sense simply using +the library, and is analogous to running a utility program or +application program. However, in a textual and legal sense, the linked +executable is a combined work, a derivative of the original library, +and the ordinary General Public License treats it as such.

+

Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better.

+

However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended +to permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to +achieve this as regards changes in header files, but we have achieved +it as regards changes in the actual functions of the Library.) The +hope is that this will lead to faster development of free libraries.

+

The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library.

+

Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one.

+

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

0. This License Agreement applies to any software +library which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Library General Public License (also called "this License"). Each +licensee is addressed as "you".

+

A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables.

+

The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".)

+

"Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library.

+

Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does and +what the program that uses the Library does.

+

1. You may copy and distribute verbatim copies of +the Library's complete source code as you receive it, in any medium, +provided that you conspicuously and appropriately publish on each copy +an appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the Library.

+

You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

+

2. You may modify your copy or copies of the +Library or any portion of it, thus forming a work based on the Library, +and copy and distribute such modifications or work under the terms of +Section 1 above, provided that you also meet all of these conditions:

+
    +
  1. The modified work must itself be a software library.
  2. +

    +
  3. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change.
  4. +

    +
  5. You must cause the whole of the work to be licensed at no charge +to all third parties under the terms of this License.
  6. +

    +
  7. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses the +facility, other than as an argument passed when the facility is +invoked, then you must make a good faith effort to ensure that, in the +event an application does not supply such function or table, the +facility still operates, and performs whatever part of its purpose +remains meaningful.
  8. +

    (For example, a function in a library to compute square roots has a +purpose that is entirely well-defined independent of the application. + Therefore, Subsection 2d requires that any application-supplied +function or table used by this function must be optional: if the +application does not supply it, the square root function must still +compute square roots.)

    +
+

These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

+

Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Library.

+

In addition, mere aggregation of another work not based on the +Library with the Library (or with a work based on the Library) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

+

3. You may opt to apply the terms of the ordinary +GNU General Public License instead of this License to a given copy of +the Library. To do this, you must alter all the notices that refer to +this License, so that they refer to the ordinary GNU General Public +License, version 2, instead of to this License. (If a newer version +than version 2 of the ordinary GNU General Public License has appeared, +then you can specify that version instead if you wish.) Do not make +any other change in these notices.

+

Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy.

+

This option is useful when you wish to copy part of the code of the +Library into a program that is not a library.

+

4. You may copy and distribute the Library (or a +portion or derivative of it, under Section 2) in object code or +executable form under the terms of Sections 1 and 2 above provided that +you accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange.

+

If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to distribute +the source code, even though third parties are not compelled to copy +the source along with the object code.

+

5. A program that contains no derivative of any +portion of the Library, but is designed to work with the Library by +being compiled or linked with it, is called a "work that uses the +Library". Such a work, in isolation, is not a derivative work of the +Library, and therefore falls outside the scope of this License.

+

However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. Section +6 states terms for distribution of such executables.

+

When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law.

+

If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.)

+

Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, whether +or not they are linked directly with the Library itself.

+

6. As an exception to the Sections above, you may +also compile or link a "work that uses the Library" with the Library to +produce a work containing portions of the Library, and distribute that +work under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications.

+

You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things:

+
    +
  1. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that uses +the Library", as object code and/or source code, so that the user can +modify the Library and then relink to produce a modified executable +containing the modified Library. (It is understood that the user who +changes the contents of definitions files in the Library will not +necessarily be able to recompile the application to use the modified +definitions.)
  2. +

    +
  3. Accompany the work with a written offer, valid for at least three +years, to give the same user the materials specified in Subsection 6a, +above, for a charge no more than the cost of performing this +distribution.
  4. +

    +
  5. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place.
  6. +

    +
  7. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy.
  8. +
+

For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major components +(compiler, kernel, and so on) of the operating system on which the +executable runs, unless that component itself accompanies the +executable.

+

It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute.

+

7. You may place library facilities that are a work +based on the Library side-by-side in a single library together with +other library facilities not covered by this License, and distribute +such a combined library, provided that the separate distribution of the +work based on the Library and of the other library facilities is +otherwise permitted, and provided that you do these two things:

+
    +
  1. Accompany the combined library with a copy of the same work based +on the Library, uncombined with any other library facilities. This +must be distributed under the terms of the Sections above.
  2. +

    +
  3. Give prominent notice with the combined library of the fact that +part of it is a work based on the Library, and explaining where to +find the accompanying uncombined form of the same work.
  4. +
+

8. You may not copy, modify, sublicense, link with, +or distribute the Library except as expressly provided under this +License. Any attempt otherwise to copy, modify, sublicense, link with, +or distribute the Library is void, and will automatically terminate +your rights under this License. However, parties who have received +copies, or rights, from you under this License will not have their +licenses terminated so long as such parties remain in full compliance.

+

9. You are not required to accept this License, +since you have not signed it. However, nothing else grants you +permission to modify or distribute the Library or its derivative works. + These actions are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Library (or any work based +on the Library), you indicate your acceptance of this License to do so, +and all its terms and conditions for copying, distributing or modifying +the Library or works based on it.

+

10. Each time you redistribute the Library (or any +work based on the Library), the recipient automatically receives a +license from the original licensor to copy, distribute, link with or +modify the Library subject to these terms and conditions. You may not +impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance +by third parties to this License.

+

11. If, as a consequence of a court judgment or +allegation of patent infringement or for any other reason (not limited +to patent issues), conditions are imposed on you (whether by court +order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. + If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Library at all. For +example, if a patent license would not permit royalty-free +redistribution of the Library by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Library.

+

If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply, and the section as a whole is intended to apply in +other circumstances.

+

It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up +to the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice.

+

This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

+

12. If the distribution and/or use of the Library +is restricted in certain countries either by patents or by copyrighted +interfaces, the original copyright holder who places the Library under +this License may add an explicit geographical distribution limitation +excluding those countries, so that distribution is permitted only in or +among countries not thus excluded. In such case, this License +incorporates the limitation as if written in the body of this License.

+

13. The Free Software Foundation may publish +revised and/or new versions of the Library General Public License from +time to time. Such new versions will be similar in spirit to the +present version, but may differ in detail to address new problems or +concerns.

+

Each version is given a distinguishing version number. If the +Library specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation.

+

14. If you wish to incorporate parts of the Library +into other free programs whose distribution conditions are incompatible +with these, write to the author to ask for permission. For software +which is copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally.

+

NO WARRANTY

+

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, +THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW +OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY +WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL +OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.

+

END OF TERMS AND CONDITIONS

+

B - Common Network Settings +

+

This appendix covers many of the popular TCP/IP network interfaces +and printer servers available on the market today.

+

Configuring a Network Interface

+

When you first install a network printer or print server on your +LAN, you need to set the Internet Protocol ("IP") address. On most +higher-end "workgroup" printers, you can set the address through the +printer control panel. However, in most cases you will want to assign +the addresses remotely from your workstation. This makes administration +a bit easier and avoids assigning duplicate addresses accidentally.

+

To setup your printer or print server for remote address assignment, +you'll need the Ethernet Media Access Control ("MAC") address, also +sometimes called a node address, and the IP address you want to use for +the device. The Ethernet MAC address can often be found on the printer +test page or bottom of the print server. + +

+

Configuring the IP Address Using ARP

+

The easiest way to set the IP address of a network device is to use +the arp(8) command. The arp sends an Address +Resolution Protocol ("ARP") packet to the specified Ethernet MAC +address, setting the network device's IP address:

+
    +
    +arp -s ip-address ethernet-address ENTER
    +arp -s host.domain.com 08:00:69:00:12:34 ENTER
    +arp -s 192.0.2.2 08:00:69:00:12:34 ENTER
    +
    +
+

Configuring the IP Address Using RARP

+

The most flexible way to remotely assign IP addresses under UNIX is +through the Reverse Address Resolution Protocol ("RARP"). RARP allows a +network device to request an IP address using its Ethernet MAC address, +and one or more RARP servers on the network will respond with an ARP +packet with the IP address the device can use.

+

RARP should be used when you have to manage many printers or print +servers, or when you have a network device that does not remember its +IP address after a power cycle. If you just have a single printer or +print server, the arp command is the way to go.

+

Some UNIX operating systems use a program called rarpd(8) + to manage RARP. Others, like Linux, support this protocol in the +kernel. For systems that provide the rarpd program you +will need to start it before RARP lookups will work:

+
    +
    +rarpd ENTER
    +
    +
+

Under IRIX you can enable this functionality by default using:

+
    +
    +chkconfig rarpd on ENTER
    +
    +
+

Both the rarpd program and kernel RARP support read a +list of Ethernet and IP addresses from the file /etc/ethers. +Each line contains the Ethernet address (colon delimited) followed by +an IP address or hostname like:

+
    +
    +08:00:69:00:12:34 myprinter.mydomain.com
    +08:00:69:00:12:34 192.0.2.2
    +
    +
+

Add a line to this file and cycle the power on the printer or print +server to set its address. + +

+

Configuring the IP Address Using BOOTP

+

The BOOTP protocol is used when you need to provide additional +information such as the location of a configuration file to the network +interface. Using the standard bootpd(8) program supplied +with UNIX you simply need to add a line to the /etc/bootptab + file; for IRIX:

+
    +
    +myprinter 08:00:69:00:12:34 192.0.2.2 myprinter.boot
    +
    +
+ + +

Newer versions of bootpd use a different format:

+
    +
    +myprinter:ha=080069001234:ip=192.0.2.2:t144=myprinter.boot
    +
    +
+

The myprinter.boot file resides in the +/usr/local/boot directory by default. If you do not need to +provide a boot file you may leave the last part of the line blank. + + +

+ + +
NOTE: +

Some versions of UNIX do not enable the BOOTP service by default. +The /etc/inetd.conf usually contains a line for the BOOTP +service that can be uncommented if needed.

+
+
+

+

Verifying the Printer Connection

+

To test that the IP address has been successfully assigned and that +the printer is properly connected to your LAN, type:

+
    +
    +ping ip-address ENTER
    +
    +
+

If the connection is working properly you will see something like:

+
    +
    +ping myprinter ENTER
    +PING myprinter (192.0.2.2): 56 data bytes
    +64 bytes from 192.0.2.2: icmp_seq=0 ttl=15 time=5 ms
    +64 bytes from 192.0.2.2: icmp_seq=1 ttl=15 time=3 ms
    +64 bytes from 192.0.2.2: icmp_seq=2 ttl=15 time=3 ms
    +64 bytes from 192.0.2.2: icmp_seq=3 ttl=15 time=3 ms
    +
    +
+

If not, verify that the printer or print server is connected to the +LAN, it is powered on, the LAN cabling is good, and the IP address is +set correctly. You can usually see the current IP address and network +status by printing a configuration or test page on the device. + +

+

Common Network Interface Settings

+

Once you have set the IP address you can access the printer or print +server using the ipp, lpd, or socket + backends. The following is a list of common network interfaces and +printer servers and the settings you should use with CUPS: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Model/ManufacturerDevice +URI(s)
Apple LaserWriterlpd:// +address/PASSTHRU
Axis w/o IPP +
(see directions)
socket://address +:9100 +
socket://address:9101 +
socket://address:9102
Axis w/IPPipp://address +/LPT1 +
ipp://address/LPT2 +
ipp://address/COM1
Castelle LANpressTM +lpd://address/pr1 +
lpd://address/pr2 +
lpd://address/pr3
DPI NETPrintlpd://address +/pr1 +
lpd://address/pr2 +
lpd://address/pr3
EFI® Fiery® RIPlpd:// +address/print
EPSON® Multiprotocol Ethernet +Interface Boardsocket://address
Extended System ExtendNET +lpd://address/pr1 +
lpd://address/pr2 +
lpd://address/pr3
Hewlett Packard JetDirect w/o IPP +socket://address:9100 +
socket://address:9101 +
socket://address:9102
Hewlett Packard JetDirect w/IPP +ipp://address/ipp +
ipp://address/ipp/port1 +
ipp://address/ipp/port2 +
ipp://address/ipp/port3
Intel® NetportExpress XL, PRO/100 +lpd://address/LPT1_PASSTHRU +
lpd://address/LPT2_PASSTHRU +
lpd://address/COM1_PASSTHRU
LexmarkTM MarkNet +lpd://address/ps
Linksys EtherFast® +
(see directions)
socket://address +:4010 +
socket://address:4020 +
socket://address:4030
Kodak®lpd://address/ps
QMS® CrownNetTM +lpd://address/ps
Tektronix® PhaserShareTM +socket://address:9100
XEROX® 4512 NIClpd:// +address/PORT1
XEROX® XNIClpd://address +/PASSTHRU
XEROX® (most others)socket:// +address:5503
+
+

+

Configuring Axis Print Servers

+

The Axis print servers can be configured using ARP, RARP, or BOOTP. +However, on models that do not provide IPP support an additional step +must be performed to configure the TCP/IP portion of the print server +for use with CUPS. + +

+

Each print server contains a configuration file named config + that contains a list of network parameters used by the server. To +modify this file you must first download it from the print server using +the ftp(1) program:

+
    +
    +ftp ip-address ENTER
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root ENTER
    +331 User name ok, need password
    +Password: pass ENTER (this is not echoed)
    +230 User logged in
    +ftp> get config ENTER
    +local: config remote: config
    +200 PORT command successful.
    +150 Opening data connection for config (192,0,2,2),
    +(mode ascii).
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
    +
+ + +

Next, edit the file with your favorite text editor and locate the +lines beginning with:

+
    +
    +RTN_OPT.     : YES
    +RTEL_PR1.    : 0
    +RTEL_PR2.    : 0
    +RTEL_PR3.    : 0
    +RTEL_PR4.    : 0
    +RTEL_PR5.    : 0
    +RTEL_PR6.    : 0
    +RTEL_PR7.    : 0
    +RTEL_PR8.    : 0
    +
    +
+ + + Change the RTN_OPT line to read: +
    +
    +RTN_OPT.     : NO
    +
    +
+ + +

This disables the Reverse TELNET protocol and enables the standard +TELNET protocol on the print server. Next, assign a port number for +each parallel and serial port on the server as follows:

+
    +
    +RTEL_PR1.    : 9100
    +RTEL_PR2.    : 9101
    +RTEL_PR3.    : 9102
    +RTEL_PR4.    : 9103
    +RTEL_PR5.    : 9104
    +RTEL_PR6.    : 9105
    +RTEL_PR7.    : 9106
    +RTEL_PR8.    : 9107
    +
    +
+ + +

This essentially makes the Axis print server look like a Hewlett +Packard JetDirect EX print server. Save the file and then upload the +new config file using the ftp command:

+
    +
    +ftp ip-address ENTER
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root ENTER
    +331 User name ok, need password
    +Password: pass ENTER (this is not echoed)
    +230 User logged in
    +ftp> put config CONFIG ENTER
    +local: config remote: CONFIG
    +200 PORT command successful.
    +150 Opening data connection for config (192,0,2,2), (mode ascii).
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> get hardreset ENTER
    +local: hardreset remote: hardreset
    +200 PORT command successful.
    +421 Axis NPS ### hard reset, closing connection.
    +ftp> quit ENTER
    +221 Goodbye.
    +
    +
+

Your Axis print server is now ready for use!

+

Configuring Linksys Print Servers

+

The Linksys print servers can be configured using ARP, RARP, or +BOOTP. Like older Axis print servers, an additional step must be +performed to configure the TCP/IP portion of the print server for use +with CUPS. + +

+

Each print server contains a configuration file named CONFIG + that contains a list of network parameters used by the server. To +modify this file you must first download it from the print server using +the ftp(1) program:

+
    +
    +ftp -n ip-address ENTER
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> get CONFIG ENTER
    +local: CONFIG remote: CONFIG
    +200 Command OK.
    +150 Open ASCII Mode Connection.
    +WARNING! 68 bare linefeeds received in ASCII mode
    +File may not have transferred correctly.
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
    +
+ + +

Next, edit the file with your favorite text editor and locate the +lines beginning with:

+
    +
    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P1
    +0140 L3_PROUT:P1
    +
    +
+

Change the port number for each parallel and serial port on the +server as follows:

+
    +
    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P2
    +0140 L3_PROUT:P3
    +
    +
+ + +

This maps each virtual printer with a physical port. Save the file +and then upload the new CONFIG file using the ftp + command:

+
    +
    +ftp -n ip-address ENTER
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> put CONFIG ENTER
    +local: CONFIG remote: CONFIG
    +200 Command OK.
    +150 Open ASCII Mode Connection.
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
    +
+

Your Linksys print server is now ready for use!

+

C - Printer Drivers

+

This appendix lists the printer drivers that are provided with CUPS.

+

Printer Drivers

+

CUPS includes the following printer drivers:

+ +

EPSON 9-pin Dot Matrix

+

The EPSON 9-pin Dot Matrix driver (epson9.ppd) supports +9-pin dot matrix printers that implement the ESC/P command set. It +provides 60x72, 120x72, and 240x72 DPI output in black only.

+

EPSON 24-pin Dot Matrix

+

The EPSON 24-pin Dot Matrix driver (epson9.ppd) supports +24-pin dot matrix printers that implement the ESC/P command set. It +provides 120x180, 180x180, 360x180, and 360x360 DPI output in black +only.

+

EPSON Stylus Color

+

The EPSON Stylus Color driver (stcolor.ppd) supports +EPSON Stylus Color printers that implement the ESC/P2 command set. It +provides 180, 360, and 720 DPI output in black and color (CMYK).

+

EPSON Stylus Photo

+

The EPSON Stylus Photo driver (stphoto.ppd) supports +EPSON Stylus Photo printers that implement the ESC/P2 command set. It +provides 180, 360, and 720 DPI output in black and color (CMYKcm).

+

HP DeskJet

+

The HP DeskJet driver (deskjet.ppd) supports HP DeskJet +printers that implement the PCL command set. It provides 150, 300, and +600 DPI output in black and color (CMYK).

+

The DeskJet printers that implement the HP-PPA command set (720C, +722C, 820C, and 1100C) are not supported due to a complete lack +of documentation and support from Hewlett Packard.

+

The duplexer provided with the HP DeskJet 900 series printers is +also not supported for similar reasons.

+

HP LaserJet

+

The HP LaserJet driver (laserjet.ppd) supports HP +LaserJet printers that implement the PCL command set. It provides 150, +300, and 600 DPI output in black only and supports the duplexer if +installed.

+

LaserJet printers that do not implement PCL (3100, 3150) are not +supported due to a complete lack of documentation and support from +Hewlett Packard.

+

D - List of Files

+

This appendix lists the files and directories that are installed for +the Common UNIX Printing System. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathnameDescription
/etc/cups/certs/The location of +authentication certificate files for local HTTP clients.
/etc/cups/classes.confThe printer classes +configuration file for the scheduler.
/etc/cups/cupsd.confThe scheduler +configuration file.
/etc/cups/interfaces/The location of +System V interface scripts for printers.
/etc/cups/mime.convsThe list of standard +file filters included with ESP Print Pro.
/etc/cups/mime.typesThe list of +recognized file types for ESP Print Pro.
/etc/cups/ppd/The location of PostScript +Printer Description ("PPD") files for printers.
/etc/cups/printers.confThe printer +configuration file for the scheduler.
/usr/bin/cancelThe System V cancel job(s) +command.
/usr/bin/disableThe System V disable +printer command.
/usr/bin/enableThe System V enable +printer command.
/usr/bin/lpThe System V print command.
/usr/bin/lpoptionsSets user-defined +printing options and defaults.
/usr/bin/lppasswdAdds, changes, or +removes Digest password accounts.
/usr/bin/lpqThe Berkeley status command.
/usr/bin/lprThe Berkeley print command.
/usr/bin/lprmThe Berkeley cancel job(s) +command.
/usr/bin/lpstatThe System V status +command.
/usr/include/cups/CUPS API header files.
/usr/lib32/libcups.a +
/usr/lib32/libcupsimage.a
Static libraries (IRIX 6.5)
/usr/lib/libcups.a +
/usr/lib/libcupsimage.a
Static libraries (all others)
/usr/lib/libcups.sl.2 +
/usr/lib/libcupsimage.sl.2
Shared libraries (HP-UX)
/usr/lib32/libcups.so.2 +
/usr/lib32/libcupsimage.so.2
Shared libraries (IRIX 6.5)
/usr/lib/libcups.so.2 +
/usr/lib/libcupsimage.so.2
Shared libraries (all others)
/usr/lib/cups/backend/Backends for +various types of printer connections.
/usr/lib/cups/cgi-bin/CGI programs for +the scheduler.
/usr/lib/cups/daemon/Daemons for polling +and LPD support.
/usr/lib/cups/filter/Filters for various +types of files.
/usr/lib/locale/The location of +language-specific message files. (System V)
/usr/lib/nls/msg/The location of +language-specific message files. (Compaq Tru64 UNIX)
/usr/share/locale/The location of +language-specific message files. (Linux, *BSD)
/usr/sbin/acceptThe accept-jobs command.
/usr/sbin/cupsdThe CUPS print scheduler.
/usr/sbin/lpadminThe System V printer +administration tool.
/usr/sbin/lpcThe Berkeley printer +administration tool.
/usr/sbin/lpinfoThe get-devices and +get-ppds command.
/usr/sbin/lpmoveThe move-jobs command.
/usr/sbin/rejectThe reject-jobs command.
/usr/share/catman/a_man/ +
/usr/share/catman/u_man/
Man pages (IRIX)
/usr/share/man/Man pages (Compaq Tru64 +UNIX, HP-UX, Solaris)
/usr/man/Man pages (all others)
/usr/share/cups/data/The location of +filter data files.
/usr/share/cups/data/testprint.psThe +PostScript test page file.
/usr/share/cups/fonts/The location of +PostScript fonts for the PostScript RIP.
/usr/share/cups/model/The location of +PostScript Printer Description ("PPD") files and interface scripts +that may be used to setup a printer queue.
/usr/share/cups/pstoraster/Other +PostScript RIP initialization files.
/usr/share/cups/pstoraster/FontmapThe +font mapping file (converts filenames to fontnames)
/usr/share/cups/templates/The location of +HTML template files for the web interfaces.
/usr/share/doc/cups/Documentation and web +page data for the scheduler.
/var/log/cups/The location of scheduler +log files.
/var/spool/cups/The location of print +files waiting to be printed.
+
+

+

E - Troubleshooting Common Problems

+

This appendix covers some of the common problems first-time users +encounter when installing and configuring CUPS.

+

Commercial support for CUPS is available from Easy Software +Products. For more information please contact us at:

+ +

My Applications Don't See the Available Printers

+

Many applications read the /etc/printcap file to get a +list of available printers.

+

The default CUPS configuration does not create the /etc/printcap + file automatically. To enable automatic creation and updating of this +file, use the Printcap directive +described in Chapter 6, "Printing System +Management".

+

CUPS Doesn't Recognize My Username or Password!

+

CUPS will ask you for a UNIX username and password when you perform +printer administration tasks remotely or via a web browser. The default +configuration requires that you use the root username and +the corresponding password to authenticate the request.

+

CUPS does not allow you to authenticate an administration request +with an account that has no password for security reasons. If you do +not have a password on your root account then you won't be +able to add printers remotely or via the web interface! + +

+

To disable password authentication you need to edit the +/etc/cups/cupsd.conf file and comment out the lines reading:

+
    +
    +AuthType Basic
    +AuthClass System
    +
    +
+ for the /admin location. Then restart the CUPS server as +described in Chapter 8, "Printing System +Management". +
+ + +
NOTE: +

Disabling password checks will allow any local user to change your +printer and class configuration, but remote administration from +another machine will still not be allowed.

+
+
+

I Can't Do Administration Tasks from Another Machine! +

+

The default CUPS configuration limits administration to the local +machine. To open up access, edit the /etc/cups/cupsd.conf + and comment out the lines reading:

+
    +
    +Order deny,allow
    +Deny from all
    +Allow from 127.0.0.1
    +
    +
+ for the /admin location. Then restart the CUPS server as +described in Chapter 8, "Printing System +Management". +
+ + +
NOTE: +

Allowing administration access from all hosts is a potential + security risk. Please read Chapter 6, +"Printing System Management" for a description of these risks and +ways to minimize them.

+
+
+ + +

I Can't Do Administration Tasks from My Web Browser! +

+

This problem is usually caused by:

+
    +
  1. not specifying the correct password for the root account.
  2. +
  3. accessing the CUPS server using the hostname or IP address of the +server without enabling remote access for administration functions. +This can be corrected by following the instructions in the +"I Can't Do Administration Tasks from Another Machine!" section +earlier in this appendix.
  4. +
  5. not setting a password on the root account. CUPS will not + authenticate a user account that does not have a password for + security reasons.
  6. +
  7. authenticating using an account other than root, but the account +you are using is not a member of the system group.
  8. +
  9. configuring CUPS to use Digest authentication, but your web +browser does not support Digest authentication.
  10. +
+

Connection Refused Messages

+

Under normal circumstances, "connection refused" messages for a +networked printer should be expected from time to time. Most network +interfaces only allow a single connection to be made at any given time +(one job at a time) and will refuse access to all other systems while +the first connection is active. CUPS automatically retries the +connection once every 30 seconds.

+

If the problem persists and you are unable to print any jobs to the +printer, verify that another machine is not maintaining a connection +with the printer, and that you have selected the proper port or printer +name for the printer.

+

Also, most external print servers will refuse connections if the +connected printer is turned off or is off-line. Verify that the +affected printer is turned on and is online.

+

Write Error Messages

+

If you get "write error" messages on a printer queue the printer +interface (usually a Hewlett Packard JetDirect interface) has timed out +and reset the network connection from your workstation.

+

The error is caused by that startup delay between the initial setup +of the printer or plotter and the first page of print data that is +sent. + +

+

To correct the problem, change the idle timeout on the interface to +at least 180 seconds or 3 minutes. To change the timeout on a Hewlett +Packard JetDirect interface, type:

+
    +
    +telnet ip-address ENTER
    +
    +Trying ip-address...
    +Connected to ip-address.
    +Escape character is `^]'.
    +
    +Please type [Return] two times, to initialize telnet configuration
    +For HELP type "?"
    +> idle-timeout: 180 ENTER
    +> quit ENTER
    +
    +
+ + diff --git a/doc/sam.pdf b/doc/sam.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fc3fa1a4ee4b72a08830fd6577aa9318164d6c11 GIT binary patch literal 243651 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

|0arEoV40^g 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 literal 0 Hc-jL100001 diff --git a/doc/sam.shtml b/doc/sam.shtml new file mode 100644 index 0000000000..ca928643e8 --- /dev/null +++ b/doc/sam.shtml @@ -0,0 +1,4317 @@ + + + + + + CUPS Software Administrators Manual + + + +

Preface

+ +

This software administrators manual provides printer administration +information for the Common UNIX Printing SystemTM +("CUPSTM"), version 1.1.7. + + + + +

Document Overview

+ +

This software administrators manual is organized into the following sections:

+ +
+ +

Notation Conventions

+ +

Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Example   Description
 
lpstat
+ lpstat(1)
   The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
 
/var
+ /usr/share/cups/data/testprint.ps
   File and directory names.
 
Request ID is Printer-123   Screen output.
 
lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
+ + +

Abbreviations

+ +The following abbreviations are used throughout this manual: + +
    +
    + +
    kb +
    Kilobytes, or 1024 bytes
      + +
    Mb +
    Megabytes, or 1048576 bytes
      + +
    Gb +
    Gigabytes, or 1073741824 bytes
      + +
    +
+ +

Other References

+ +
    +
    + +
    CUPS Software Programmers Manual + +
    A programmer guide for interfacing with and/or extending the CUPS + software.
      + +
    CUPS Software Users Manual + +
    An end-user guide for using the CUPS software.
      + +
    +
+ + + + + +

2 - Building and Installing CUPS

+ +

This chapter shows how to build and install the Common UNIX Printing System. +If you are installing a binary distribution from the CUPS web site, proceed to +the section titled, Installing a Binary Distribution. + +

Installing a Source Distribution

+ +

This section describes how to compile and install CUPS on your system +from the source code. + +

Requirements

+ +

You'll need ANSI-compliant C and C++ compilers to build CUPS on your +system. As its name implies, CUPS is designed to run on the UNIX +operating system, however the CUPS interface library and most of the +filters and backends supplied with CUPS should also compile and run +under Microsoft Windows. + +

For the image file filters and PostScript RIP, you'll need the JPEG, +PNG, TIFF, and ZLIB libraries. CUPS will build without these, but with +significantly reduced functionality. Easy Software Products maintains a +mirror of the current versions of these libraries at: + +

+ +

If you make changes to the man pages you'll need GNU groff or another +nroff-like package. GNU groff is available from: + +

+ +

The documentation is formatted using the HTMLDOC software. If you need to +make changes you can get the HTMLDOC software from: + +

+ +

Compiling CUPS

+ +

CUPS uses GNU autoconf to configure the makefiles and source code +for your system. Type the following command to configure CUPS for your +system: + +

    +./configure ENTER
    +
+ +

The default installation will put the CUPS software in the +/etc, /usr, and /var directories on +your system, which will overwrite any existing printing commands on +your system. Use the --prefix option to install the CUPS +software in another location: + +

    +./configure --prefix=/some/directory ENTER
    +
+ +

If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a +system default location (typically /usr/include and +/usr/lib) you'll need to set the CFLAGS, +CXXFLAGS, and LDFLAGS environment variables +prior to running configure: + +

    +setenv CFLAGS "-I/some/directory" ENTER
    +setenv CXXFLAGS "-I/some/directory" ENTER
    +setenv LDFLAGS "-L/some/directory" ENTER
    +setenv DSOFLAGS "-L/some/directory" ENTER
    +./configure ... ENTER
    +
+ +

or: + +

    +CFLAGS="-I/some/directory"; export CFLAGS ENTER
    +CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER
    +LDFLAGS="-L/some/directory"; export LDFLAGS ENTER
    +DSOFLAGS="-L/some/directory"; export DSOFLAGS ENTER
    +./configure ... ENTER
    +
+ +

To enable support for encryption, you'll also want to add the +"--enable-ssl" option: + +

    +./configure --enable-ssl
    +
+ +

SSL and TLS support require the OpenSSL library, available at: + +

+ +

Once you have configured things, just type: + +

    +make ENTER
    +
+ +

to build the software. + + +

Installing the Software

+ +

Use the "install" target to install the software: + +

    +make install ENTER
    +
+ +
+ + + +
+ WARNING: + +

Installing CUPS will overwrite your existing printing + system. If you experience difficulties with the CUPS software + and need to go back to your old printing system, you will need + to reinstall the old printing system from your operating system CDs. +

+ +

Running the Software

+ +

Once you have installed the software you can start the CUPS server by +typing: + +

    +/usr/sbin/cupsd ENTER
    +
+ + +

Installing a Binary Distribution

+ +

CUPS comes in a variety of binary distribution formats. Easy +Software Products provides binaries in TAR format with installation and +removal scripts ("portable" distributions), and in RPM and DPKG formats +for Red Hat and Debian-based distributions. Portable distributions are +available for all platforms, while the RPM and DPKG distributions are +only available for Linux. + +

+ + + +
+ WARNING: + +

Installing CUPS will overwrite your existing printing + system. If you experience difficulties with the CUPS software + and need to go back to your old printing system, you will need + to remove the CUPS software with the provided script and/or + reinstall the old printing system from your operating system CDs. +

+ + +

Installing a Portable Distribution

+ +

To install the CUPS software from a portable distribution you will +need to be logged in as root; doing an su is good enough. +Once you are the root user, run the installation script with: + +

    +./cups.install ENTER
    +
+ +

After asking you a few yes/no questions the CUPS software will be +installed and the scheduler will be started automatically. + + +

Installing an RPM Distribution

+ +

To install the CUPS software from an RPM distribution you will need +to be logged in as root; doing an su is good enough. Once +you are the root user, run RPM with: + +

    +rpm -e lpr
    +rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER
    +
+ +

After a short delay the CUPS software will be +installed and the scheduler will be started automatically. + +

Installing an Debian Distribution

+ +

To install the CUPS software from a Debian distribution you will +need to be logged in as root; doing an su is good enough. +Once you are the root user, run dpkg with: + +

    +dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER
    +
+ +

After a short delay the CUPS software will be installed and the +scheduler will be started automatically. + + +

3 - Printer Management

+ +

This chapter describes how to add your first printer and how to +manage your printers. + +

The Basics

+ +

Each printer queue has a name associated with it; the printer name +must start with a letter and can contain up to 127 letters, numbers, +and the underscore (_). Case is not significant, e.g. "PRINTER", "Printer", +and "printer" are considered to be the same name. + +

Printer queues also have a device associated with them. The device can be +a parallel port, a network interface, and so forth. Devices within CUPS use +Uniform Resource Identifiers ("URIs") which are a more general form of +Uniform Resource Locators ("URLs") that are used in your web browser. For +example, the first parallel port in Linux usually uses a device URI of +parallel:/dev/lp1. + + +

You can see a complete list of supported devices by running the +lpinfo(8) command: + +

    +lpinfo -v ENTER
    +file file
    +network socket
    +network http
    +network ipp
    +network lpd
    +direct parallel:/dev/lp1
    +serial serial:/dev/ttyS1?baud=115200
    +serial serial:/dev/ttyS2?baud=115200
    +direct usb:/dev/usb/lp0
    +network smb
    +
+ +

The -v option specifies that you want a list of available +devices. The first word in each line is the type of device (direct, file, +network, or serial) and is followed by the device URI or method name for +that device. File devices have device URIs of the form +file:/directory/filename while network devices use the more +familiar method://server or method://server/path +format. + +

Finally, printer queues usually have a PostScript Printer Description +("PPD") file associated with them. PPD files describe the capabilities of +each printer, the page sizes supported, etc., and are used for PostScript +and non-PostScript printers. CUPS includes PPD files for HP LaserJet, HP +DeskJet, EPSON 9-pin, EPSON 24-pin, and EPSON Stylus printers. + +

Adding Your First Printer

+ +

CUPS provides two methods for adding printers: a command-line +program called lpadmin(8) and a Web interface. The +lpadmin command allows you to perform most printer +administration tasks from the command-line and is located in +/usr/sbin. The Web interface is located at: + +

+ +

and steps you through printer configuration. If you don't like +command-line interfaces, try the Web interface instead. + +

Adding Your First Printer from the Command-Line

+ +

Run the lpadmin command with the -p option to add a +printer to CUPS: + +

    +/usr/sbin/lpadmin -p printer -E -v device -m ppd ENTER
    +
+ +

For an HP DeskJet printer connected to the parallel port this would look +like: + +

    +/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER
    +
+ +

Similarly, an HP LaserJet printer using a JetDirect network interface at +IP address 11.22.33.44 would be added with the command: + +

    +/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER
    +
+ +

As you can see, deskjet.ppd and laserjet.ppd are +the PPD files for the HP DeskJet and HP LaserJet drivers included with CUPS. +You'll find a complete list of PPD files and the printers they will work with +in Appendix C, "Printer Drivers". + +

Adding Your First Printer from the Web

+ +

The CUPS web server provides a user-friendly "wizard" interface for +adding your printers. Rather than figuring out which device URI and PPD file +to use, you can instead click on the appropriate listings and fill in some +simple information. Enter the following URL in your web browser to begin: + +

+ +

Click on the Add Printer button to add a printer. + +

Managing Printers from the Command-Line

+ +

The lpadmin command enables you to perform most printer +administration tasks from the command-line. You'll find lpadmin +in the /usr/sbin directory. + +

Adding and Modifying Printers

+ +

Run the lpadmin command with the -p option +to add or modify a printer: + +

    +/usr/sbin/lpadmin -p printer options ENTER
    +
+ +

The options arguments can be any of the following: + +

    +
    + +
    -c class + +
    Adds the named printer to printer class class. + If the class does not exist then it is created. + +
    -i interface + +
    Copies the named interface script to the printer. + Interface scripts are used by System V printer drivers. Since + all filtering is disabled when using an interface script, scripts + generally should not be used unless there is no other driver for + a printer. + +
    -m model + +
    Specifies a standard printer driver which is usually a PPD + file. A list of all available models can be displayed using the + lpinfo command with the -m option. A + list of printer drivers included with CUPS can be found in + Appendix C, "Printer Drivers". + +
    -r class + +
    Removes the named printer from printer class class. + If the resulting class becomes empty then it is removed. + +
    -v device-uri + +
    Sets the device for communicating with the printer. If a + job is currently printing on the named printer then the job + will be restarted and sent to the new device. + +
    -D info + +
    Provides a textual description of the printer, e.g. + "John's Personal Printer". + +
    -E + +
    Enables the printer and accepts job. This option is + equivalent to running the enable(1) and + accept(8) commands on the printer. + +
    -L location + +
    Provides a textual location for the printer, e.g. + "Computer Lab 5". + +
    -P ppd-file + +
    Specifies a local PPD file for the printer driver. + +
    +
+ +

Deleting Printers

+ +

Run the lpadmin command with the -x option +to delete a printer: + +

    +/usr/sbin/lpadmin -x printer ENTER
    +
+ +

Setting the Default Printer

+ +

Run the lpadmin command with the -d option +to set a default printer: + +

    +/usr/sbin/lpadmin -d printer ENTER
    +
+ +

The default printer can be overridden by the user using the +lpoptions(1) command. + +

Starting and Stopping Printers

+ +

The enable and disable commands start and stop +printer queues, respectively: + +

    +/usr/bin/enable printer ENTER
    +/usr/bin/disable printer ENTER
    +
+ +

Printers that are disabled may still accept jobs for printing, but won't +actually print any files until they are restarted. This is useful if the +printer malfunctions and you need time to correct the problem. Any queued +jobs are printed after the printer is enabled (started). + +

Accepting and Rejecting Print Jobs

+ +

The accept and reject commands accept and reject +print jobs for the named printer, respectively: + +

    +/usr/sbin/accept printer ENTER
    +/usr/sbin/reject printer ENTER
    +
+ +

As noted above, a printer can be stopped but accepting new print +jobs. A printer can also be rejecting new print jobs while it finishes +those that have been queued. This is useful for when you must perform +maintenance on the printer and will not have it available to users for +a long period of time. + +

Managing Printers from the Web

+ +

The Web interface is located at: + +

+ +

From there you can perform all printer management tasks with a few +simple mouse clicks. + + +

4 - Printer Classes

+ +

This chapter describes what printer classes are and how to manage them. + +

The Basics

+ +

CUPS provides collections of printers called printer classes. Jobs +sent to a class are forwarded to the first available printer in the class. +Classes can themselves be members of other classes, so it is possible for +you to define very large, distributed printer classes for high-availability +printing. + +

CUPS also supports implicit classes. Implicit classes work just +like printer classes, but they are created automatically based upon the +available printers and classes on the network. This allows you to setup +multiple print servers with identical printer configurations and have the +client machines send their print jobs to the first available server. If +one or more servers go down, the jobs are automatically redirected to the +servers that are running, providing fail-safe printing. + +

Managing Printer Classes from the Command-Line

+ +

Run the lpadmin command with the -p and -c options +to add a printer to a class: + +

    +/usr/sbin/lpadmin -p printer -c class ENTER
    +
+ +

The class is created automatically if it doesn't exist. To remove a +printer from a class use the -r option: + +

    +/usr/sbin/lpadmin -p printer -r class ENTER
    +
+ +

To remove the entire class just use the -x option: + +

    +/usr/sbin/lpadmin -x class ENTER
    +
+ +

Managing Printer Classes from the Web Interface

+ +

The Web interface is located at: + +

+ +

The Add Class and Modify Class interfaces provide a +list of available printers; click on the printers of interest to add them to +the class. + +

Implicit Classes

+ +

A noted earlier, implicit classes are created automatically from the +available network printers and classes. To disable this functionality, +set the ImplicitClasses +directive to Off in the cupsd.conf file. You +will find more information on doing this in +Chapter 6, "Printing System +Management". + + +

5 - Client Setup

+ +

This chapter discusses several ways to configure CUPS clients for +printing. + +

The Basics

+ +

A client is any machine that sends print jobs to another machine for +final printing. Clients can also be servers if they communicate directly with +any printers of their own. + +

CUPS supports several methods of configuring client machines: + +

+ +

Manual Configuration of Print Queues

+ +

The most tedious method of configuring client machines is to configure +each remote queue by hand using the lpadmin command: + +

    +lpadmin -p printer -E -v ipp://server/printers/printer ENTER
    +
+ +

The printer name is the name of the printer on the server +machine. The server name is the hostname or IP address of the +server machine. Repeat the lpadmin command for each remote +printer you wish to use. + +

Specifying a Single Server for Printing

+ +

CUPS can be configured to run without a local spooler and send all +jobs to a single server. However, if that server goes down then all +printing will be disabled. Use this configuration only as absolutely needed. + +

The default server is normally "localhost". To override the default +server create a file named /etc/cups/client.conf and add +a line reading: + +

    +ServerName server
    +
+ +

to the file. The server name can be the hostname or IP address +of the default server. + +

The default server can also be customized on a per-user basis. To set a +user-specific server create a file named ~/.cupsrc and add a line +reading: + +

    +ServerName server
    +
+ +

to the file. The server name can be the hostname or IP +address of the default server. + +

Automatic Configuration of Print Queues

+ +

CUPS supports automatic client configuration of printers on the same +subnet. To configure printers on the same subnet, do nothing. +Each client should see the available printers within 30 seconds +automatically. The printer and class lists are updated automatically as +printers and servers are added or removed. + +

If you want to see printers on other subnets as well, use the +BrowsePoll directive as +described next. + +

Specifying Multiple Servers for Printing

+ +

If you have CUPS servers on different subnets, then you should configure +CUPS to poll those servers. Polling provides the benefits of automatic +configuration without significant configuration on the clients, and multiple +clients on the same subnet can share the same configuration information. + +

Polling is enabled by specifying one or more +BrowsePoll directives in the +/etc/cups/cupsd.conf file. For information on making these +changes, see Chapter 6, "Printing System +Management". + + +

6 - Printing System Management

+ +

This chapter shows how you can configure the CUPS server. + +

The Basics

+ +

Several text files are used to configure CUPS. All of the server +configuration files are located in the /etc/cups directory: + +

    +
    + + +
    classes.conf + +
    This file contains information on each printer class. + Normally you manipulate this file using the + lpadmin command or the Web interface.
      + + +
    client.conf + +
    This file provides the default server name for client + machines. See Chapter 5, "Client + Setup" for more information.
      + + +
    cupsd.conf + +
    This file controls how the CUPS server + (/usr/sbin/cupsd) operates and is normally edited by + hand.
      + + +
    mime.convs + +
    This file contains a list of standard file conversion filters + and their costs. You normally do not edit this file.
      + + +
    mime.types + +
    This file contains a list of standard file formats and how to + recognize them. You normally do not edit this file.
      + + +
    printers.conf + +
    This file contains information on each printer. Normally + you manipulate this file using the lpadmin command + or the Web Interface.
      + +
    +
+ +

Restarting the CUPS Server

+ +

Once you have made a change to a configuration file you need to +restart the CUPS server by sending it a HUP signal or using the +supplied initialization script. The CUPS distributions install the +script in the init.d directory with the name +cups. The location varies based upon the operating system: + +

    +/etc/rc.d/init.d/cups restart ENTER
    +/etc/init.d/cups restart ENTER
    +/sbin/init.d/cups restart ENTER
    +
+ +

Changing the Server Configuration

+ +

The /etc/cups/cupsd.conf file contains configuration +directives that control how the server functions. Each directive +is listed on a line by itself followed by its value. Comments are +introduced using the number sign ("#") character at the beginning of a +line. Since the server configuration file consists of plain text, you +can use your favorite text editor to make changes to it. + + +

Server Directives

+ +

The cupsd.conf file contains many directives that +determine how the server operates: + +

+ + +

AccessLog

+
+ +

Examples

+ +
    +AccessLog /var/log/cups/access_log
    +AccessLog /var/log/cups/access_log-%s
    +AccessLog syslog
    +
+ +

Description

+ +

The AccessLog directive sets the name of the access log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +access log file is stored in "common log format" and can be used by any +web access reporting tool to generate a report on CUPS server activity. + +

The server name can be included in the filename by using +%s in the name. + +

The special name "syslog" can be used to send the access information +to the system log instead of a plain file. + +

The default access log file is /var/log/cups/access_log. + + +

Allow

+
+ +

Examples

+ +
    +Allow from All
    +Allow from None
    +Allow from *.domain.com
    +Allow from .domain.com
    +Allow from host.domain.com
    +Allow from nnn.*
    +Allow from nnn.nnn.*
    +Allow from nnn.nnn.nnn.*
    +Allow from nnn.nnn.nnn.nnn
    +Allow from nnn.nnn.nnn.nnn/mm
    +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
+ +

Description

+ +

The Allow directive specifies a hostname, IP address, +or network that is allowed access to the server. Allow +directives are cummulative, so multiple Allow directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mmnetmaskmmnetmask
00.0.0.08255.0.0.0
1128.0.0.016255.255.0.0
2192.0.0.024255.255.255.0
......32255.255.255.255
+ +

The Allow directive must appear inside a +Location directive. + + +

AuthClass

+
+ +

Examples

+ +
    +AuthClass Anonymous
    +AuthClass User
    +AuthClass System
    +AuthClass Group
    +
+ +

Description

+ +

The AuthClass directive defines what level of authentication +is required: + +

    + +
  • Anonymous - No authentication should be performed + (default.) + +
  • User - A valid username and password is required. + +
  • System - A valid username and password is + required, and the username must belong to the "sys" group; this + can be changed using the + SystemGroup directive. + +
  • Group - A valid username and password is + required, and the username must belong to the group named by + the AuthGroupName directive. + +
+ +

The AuthClass directive must appear inside a +Location directive. + + +

AuthGroupName

+
+ +

Examples

+ +
    +AuthGroupName mygroup
    +AuthGroupName lp
    +
+ +

Description

+ +

The AuthGroupName directive sets the group to use for +Group authentication. + +

The AuthGroupName directive must appear inside a +Location directive. + + +

AuthType

+
+ +

Examples

+ +
    +AuthType None
    +AuthType Basic
    +AuthType Digest
    +
+ +

Description

+ +

The AuthType directive defines the type of authentication to +perform: + +

    + +
  • None - No authentication should be performed + (default.) + +
  • Basic - Basic authentication should be + performed using the UNIX password and group files. + +
  • Digest - Digest authentication should be + performed using the /etc/cups/passwd.md5 file. + +
+ +

When using Basic or Digest authentication, +clients connecting through the localhost interface can also +authenticate using certificates. + +

The AuthType directive must appear inside a +Location directive. + + +

AutoPurgeJobs

+
+ +

Examples

+ +
    +AutoPurgeJobs Yes
    +AutoPurgeJobs No
    +
+ +

Description

+ +

The AutoPurgeJobs directive specifies whether or not to purge +completed jobs once they are no longer required for quotas. This option has +no effect if quotas are not enabled. The default setting is No. + + +

BrowseAddress

+
+ +

Examples

+ +
    +BrowseAddress 255.255.255.255:631
    +BrowseAddress 192.0.2.255:631
    +BrowseAddress host.domain.com:631
    +
+ +

Description

+ +

The BrowseAddress directive specifies an address to +send browsing information to. Multiple BrowseAddress +directives can be specified to send browsing information to different +networks or systems. + +

The default address is 255.255.255.255:631 which will +broadcast the information to all networks the server is connected to. + +

+ + + +
+ NOTE: + +

If you are using HP-UX 10.20 and a subnet that is not 24, + 16, or 8 bits, printer browsing (and in fact all broadcast + reception) will not work. This problem appears to be fixed in + HP-UX 11.0. +

+ + +

BrowseAllow

+
+ +

Examples

+ +
    +BrowseAllow from all
    +BrowseAllow from none
    +BrowseAllow from 192.0.2
    +BrowseAllow from 192.0.2.0/24
    +BrowseAllow from 192.0.2.0/255.255.255.0
    +BrowseAllow from *.domain.com
    +
+ +

Description

+ +

The BrowseAllow directive specifies a system or network +to accept browse packets from. The default is to accept browse packets +from all hosts. + +

Host and domain name matching require that you enable the +HostNameLookups directive. + +

IP address matching supports exact matches, partial addresses that +match networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0, +or network addresses using the specified netmask or bit count. + + +

BrowseDeny

+
+ +

Examples

+ +
    +BrowseDeny from all
    +BrowseDeny from none
    +BrowseDeny from 192.0.2
    +BrowseDeny from 192.0.2.0/24
    +BrowseDeny from 192.0.2.0/255.255.255.0
    +BrowseDeny from *.domain.com
    +
+ +

Description

+ +

The BrowseDeny directive specifies a system or network +to reject browse packets from. The default is to deny browse packets +from no hosts. + +

Host and domain name matching require that you enable the +HostNameLookups directive. + +

IP address matching supports exact matches, partial addresses that +match networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0, +or network addresses using the specified netmask or bit count. + + +

BrowseOrder

+
+ +

Examples

+ +
    +BrowseOrder allow,deny
    +BrowseOrder deny,allow
    +
+ +

Description

+ +

The BrowseOrder directive specifies the order of allow/deny +processing. The default order is deny,allow: + +

    + +
  • allow,deny - Browse packets are accepted unless + specifically denied. + +
  • deny,allow - Browse packets are rejected unless + specifically allowed. + +
+ + +

BrowseInterval

+
+ +

Examples

+ +
    +BrowseInterval 0
    +BrowseInterval 30
    +
+ +

Description

+ +

The BrowseInterval directive specifies the maximum amount of +time between browsing updates. Specifying a value of 0 seconds disables +outgoing browse updates but allows a server to receive printer information +from other hosts. + +

The BrowseInterval value should always be less than the +BrowseTimeout value. Otherwise +printers and classes will disappear from client systems between updates. + + +

BrowsePoll

+
+ +

Examples

+ +
    +BrowsePoll 192.0.2.2:631
    +BrowsePoll host.domain.com:631
    +
+ +

Description

+ +

The BrowsePoll directive polls a server for available +printers once every +BrowseInterval seconds. +Multiple BrowsePoll directives can be specified to poll +multiple servers. + +

If BrowseInterval is set to 0 then the server is polled +once every 30 seconds. + + +

BrowsePort

+
+ +

Examples

+ +
    +BrowsePort 631
    +BrowsePort 9999
    +
+ +

Description

+ +

The BrowsePort directive specifies the UDP port number +used for browse packets. The default port number is 631. + +

+ + + +
+ NOTE: + +

You must set the BrowsePort to the same value + on all of the systems that you want to see. +

+ + +

BrowseRelay

+
+ +

Examples

+ +
    +BrowseRelay 193.0.2.1 192.0.2.255
    +BrowseRelay 193.0.2.0/255.255.255.0 192.0.2.255
    +BrowseRelay 193.0.2.0/24 192.0.2.255
    +BrowseRelay *.domain.com 192.0.2.255
    +BrowseRelay host.domain.com 192.0.2.255
    +
+ +

Description

+ +

The BrowseRelay directive specifies source and destination +addresses for relaying browsing information from one host or network to +another. Multiple BrowseRelay directives can be specified +as needed. + +

BrowseRelay is typically used on systems that bridge +multiple subnets using one or more network interfaces. It can also be +used to relay printer information from polled servers with the line: + +

    +BrowseRelay 127.0.0.1 255.255.255.255
    +
+ +

This effectively provides access to printers on a WAN for all clients +on the LAN(s). + + +

BrowseShortNames

+
+ +

Examples

+ +
    +BrowseShortNames Yes
    +BrowseShortNames No
    +
+ +

Description

+ +

The BrowseShortNames directive specifies whether or not +short names are used for remote printers when possible. Short names are +just the remote printer name, without the server ("printer"). If more than +one remote printer is detected with the same name, the printers will have +long names ("printer@server1", "printer@server2".) + +

The default value for this option is Yes. + + +

BrowseTimeout

+
+ +

Examples

+ +
    +BrowseTimeout 300
    +BrowseTimeout 60
    +
+ +

Description

+ +

The BrowseTimeout directive sets the timeout for +printer or class information that is received in browse packets. Once a +printer or class times out it is removed from the list of available +destinations. + +

The BrowseTimeout value should always be greater than the +BrowseInterval value. Otherwise +printers and classes will disappear from client systems between updates. + + +

Browsing

+
+ +

Examples

+ +
    +Browsing On
    +Browsing Off
    +
+ +

Description

+ +

The Browsing directive controls whether or not network printer +browsing is enabled. The default setting is On. + +

+ + + +
+ NOTE: + +

If you are using HP-UX 10.20 and a subnet that is not 24, + 16, or 8 bits, printer browsing (and in fact all broadcast + reception) will not work. This problem appears to be fixed in + HP-UX 11.0. +

+ + +

Classification

+
+ +

Examples

+ +
    +Classification
    +Classification classified
    +Classification confidential
    +Classification secret
    +Classification topsecret
    +Classification unclassified
    +
+ +

Description

+ +

The Classification directive sets the classification level +on the server. When this option is set, at least one of the banner pages +is forced to the classification level, and the classification is placed +on each page of output. The default is no classification level. + + +

DataDir

+
+ +

Examples

+ +
    +DataDir /usr/share/cups
    +
+ +

Description

+ +

The DataDir directive sets the directory to use for data +files. + + +

DefaultCharset

+
+ +

Examples

+ +
    +DefaultCharset utf-8
    +DefaultCharset iso-8859-1
    +DefaultCharset windows-1251
    +
+ +

Description

+ +

The DefaultCharset directive sets the default character set +to use for client connections. The default character set is +utf-8 but is overridden by the character set for the language +specified by the client or the DefaultLanguage directive. + + +

DefaultLanguage

+
+ +

Examples

+ +
    +DefaultLanguage de
    +DefaultLanguage en
    +DefaultLanguage es
    +DefaultLanguage fr
    +DefaultLanguage it
    +
+ +

Description

+ +

The DefaultLanguage directive specifies the default language +to use for client connections. Setting the default language also sets the +default character set if a language localization file exists for it. The +default language is "en" for English. + + +

Deny

+
+ +

Examples

+ +
    +Deny from All
    +Deny from None
    +Deny from *.domain.com
    +Deny from .domain.com
    +Deny from host.domain.com
    +Deny from nnn.*
    +Deny from nnn.nnn.*
    +Deny from nnn.nnn.nnn.*
    +Deny from nnn.nnn.nnn.nnn
    +Deny from nnn.nnn.nnn.nnn/mm
    +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
+ +

Description

+ +

The Deny directive specifies a hostname, IP address, or +network that is allowed access to the server. Deny +directives are cummulative, so multiple Deny directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mmnetmaskmmnetmask
00.0.0.08255.0.0.0
1128.0.0.016255.255.0.0
2192.0.0.024255.255.255.0
......32255.255.255.255
+ +

The Deny directive must appear inside a +Location directive. + + +

DocumentRoot

+
+ +

Examples

+ +
    +DocumentRoot /usr/share/doc/cups
    +DocumentRoot /foo/bar/doc/cups
    +
+ +

Description

+ +

The DocumentRoot directive specifies the location of +web content for the HTTP server in CUPS. If an absolute path is not +specified then it is assumed to be relative to the +ServerRoot directory. The +default directory is /usr/share/doc/cups. + +

Documents are first looked up in a sub-directory for the primary +language requested by the client (e.g. /usr/share/doc/cups/fr/...) +and then directly under the DocumentRoot directory +(e.g. /usr/share/doc/cups/...), so it is possible to localize +the web content by providing subdirectories for each language needed. + + +

Encryption

+
+ +

Examples

+ +
    +Encryption Never
    +Encryption IfRequested
    +Encryption Required
    +Encryption Always
    +
+ +

Description

+ +

The Encryption directive must appear instead a +Location +section and specifies the encryption settings for that location. +The default setting is IfRequested for all locations. + + +

ErrorLog

+
+ +

Examples

+ +
    +ErrorLog /var/log/cups/error_log
    +ErrorLog /var/log/cups/error_log-%s
    +ErrorLog syslog
    +
+ +

Description

+ +

The ErrorLog directive sets the name of the error log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default error log file is /var/log/cups/error_log. + +

The server name can be included in the filename by using +%s in the name. + +

The special name "syslog" can be used to send the error information +to the system log instead of a plain file. + + +

FilterLimit

+
+ +

Examples

+ +
    +FilterLimit 0
    +FilterLimit 200
    +FilterLimit 1000
    +
+ +

Description

+ +

The FilterLimit directive sets the maximum cost +of all running job filters. It can be used to limit the number +of filter programs that are run on a server to minimize disk, +memory, and CPU resource problems. A limit of 0 disables filter +limiting. + +

An average print to a non-PostScript printer needs a filter +limit of about 200. A PostScript printer needs about half that +(100). Setting the limit below these thresholds will effectively +limit the scheduler to printing a single job at any time. + +

The default limit is 0. + + +

FontPath

+
+ +

Examples

+ +
    +FontPath /foo/bar/fonts
    +FontPath /usr/share/cups/fonts:/foo/bar/fonts
    +
+ +

Description

+ +

The FontPath directive specifies the font path to use when +searching for fonts. The default font path is +/usr/share/cups/fonts. + + +

Group

+
+ +

Examples

+ +
    +Group sys
    +Group system
    +Group root
    +
+ +

Description

+ +

The Group directive specifies the UNIX group that +filter and CGI programs run as. The default group is sys, +system, or root depending on the operating +system. + + +

HostNameLookups

+
+ +

Examples

+ +
    +HostNameLookups On
    +HostNameLookups Off
    +HostNameLookups Double
    +
+ +

Description

+ +

The HostNameLookups directive controls whether +or not CUPS looks up the hostname for connecting clients. The +Double setting causes CUPS to verify that the +hostname resolved from the address matches one of the addresses +returned for that hostname. Double lookups also +prevent clients with unregistered addresses from connecting +to your server. + +The default is Off to avoid the potential server +performance problems with hostname lookups. Set this option to +On or Double only if absolutely +required. + + +

ImplicitClasses

+
+ +

Examples

+ +
    +ImplicitClasses On
    +ImplicitClasses Off
    +
+ +

Description

+ +

The ImplicitClasses directive controls whether implicit +classes are created based upon the available network printers and classes. +The default setting is On but is automatically turned +Off if Browsing is +turned Off. + + +

KeepAlive

+
+ +

Examples

+ +
    +KeepAlive On
    +KeepAlive Off
    +
+ +

Description

+ +

The KeepAlive directive controls whether or not to support +persistent HTTP connections. The default is On. + +

HTTP/1.1 clients automatically support persistent connections, while +HTTP/1.0 clients must specifically request them using the +Keep-Alive attribute in the Connection: +field of each request. + + +

KeepAliveTimeout

+
+ +

Examples

+ +
    +KeepAliveTimeout 60
    +KeepAliveTimeout 30
    +
+ +

Description

+ +

The KeepAliveTimeout directive controls how long a +persistent HTTP connection will remain open after the last request. The +default is 60 seconds. + + +

Limit

+
+ +

Examples

+ +
    +<Limit GET POST>
    +...
    +</Limit>
    +
    +<Limit ALL>
    +...
    +</Limit>
    +
+ +

Description

+ +

The Limit directive groups access control directives for +specific types of HTTP requests and must appear inside a +Location section. Access can be limited +for individual request types (DELETE, GET, +HEAD, OPTIONS, POST, PUT, +and TRACE) or for all request types (ALL). The +request type names are case-sensitive for compatibility with Apache. + + +

LimitExcept

+
+ +

Examples

+ +
    +<LimitExcept GET POST>
    +...
    +</LimitExcept>
    +
+ +

Description

+ +

The LimitExcept directive groups access control directives for +specific types of HTTP requests and must appear inside a +Location section. Unlike the +Limit directive, LimitExcept +restricts access for all requests except those listed on the +LimitExcept line. + + +

LimitRequestBody

+
+ +

Examples

+ +
    +LimitRequestBody 10485760
    +LimitRequestBody 10m
    +LimitRequestBody 0
    +
+ +

Description

+ +

The LimitRequestBody directive controls the maximum size of +print files, IPP requests, and HTML form data in HTTP POST requests. The +default limit is 0 which disables the limit check. + +

Also see the identical +MaxRequestSize directive. + + +

Listen

+
+ +

Examples

+ +
    +Listen 127.0.0.1:631
    +Listen 192.0.2.1:631
    +
+ +

Description

+ +

The Listen directive specifies a network address and port +to listen for connections. Multiple Listen directives can be +provided to listen on multiple addresses. + +

The Listen directive is similar to the +Port directive but allows you to restrict +access to specific interfaces or networks. + + +

Location

+
+ +

Examples

+ +
    +<Location />
    +...
    +</Location>
    +
    +<Location /admin>
    +...
    +</Location>
    +
    +<Location /printers/name>
    +...
    +</Location>
    +
+ +

Description

+ +

The Location directive specifies access control and +authentication options for the specified HTTP resource or path. More +information can be found later in this chapter in +"Printing System Security". + + +

LogLevel

+
+ +

Examples

+ +
    +LogLevel none
    +LogLevel emerg
    +LogLevel alert
    +LogLevel crit
    +LogLevel error
    +LogLevel warn
    +LogLevel notice
    +LogLevel info
    +LogLevel debug
    +LogLevel debug2
    +
+ +

Description

+ +

The LogLevel directive specifies the level of logging +for the ErrorLog file. The +following values are recognized (each level logs everything under the +preceding levels): + +

    + +
  • none - Log nothing. + +
  • emerg - Log emergency conditions that prevent the + server from running. + +
  • alert - Log alerts that must be handled immediately. + +
  • crit - Log critical errors that don't prevent + the server from running. + +
  • error - Log general errors. + +
  • warn - Log errors and warnings. + +
  • notice - Log temporary error conditions. + +
  • info - Log all requests and state changes (default). + +
  • debug - Log basic debugging information. + +
  • debug2 - Log all debugging information. + +
+ + +

MaxClients

+
+ +

Examples

+ +
    +MaxClients 100
    +MaxClients 1024
    +
+ +

Description

+ +

The MaxClients directive controls the maximum number of +simultaneous clients that will be allowed by the server. The default is +100 clients. + +

+ + + +
+ NOTE: + +

Since each print job requires a file descriptor for the + status pipe, the CUPS server internally limits the + MaxClients value to 1/3 of the available file descriptors + to avoid possible problems when printing large numbers of jobs. +

+ + +

MaxJobs

+
+ +

Examples

+ +
    +MaxJobs 100
    +MaxJobs 9999
    +MaxJobs 0
    +
+ +

Description

+ +

The MaxJobs directive controls the maximum number of jobs +that are kept in memory. Once the number of jobs reaches the limit, the +oldest completed job is automatically purged from the system to make room +for the new one. If all of the known jobs are still pending or active then +the new job will be rejected. + +

Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

MaxJobsPerPrinter

+
+ +

Examples

+ +
    +MaxJobsPerPrinter 100
    +MaxJobsPerPrinter 9999
    +MaxJobsPerPrinter 0
    +
+ +

Description

+ +

The MaxJobsPerPrinter directive controls the maximum number of active jobs +that are allowed for each printer or class. Once a printer or class reaches the limit, new jobs will be +rejected until one of the active jobs is completed, stopped, aborted, or cancelled. + +

Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

MaxJobsPerUser

+
+ +

Examples

+ +
    +MaxJobsPerUser 100
    +MaxJobsPerUser 9999
    +MaxJobsPerUser 0
    +
+ +

Description

+ +

The MaxJobsPerUser directive controls the maximum number of active jobs +that are allowed for each user. Once a user reaches the limit, new jobs will be +rejected until one of the active jobs is completed, stopped, aborted, or cancelled. + +

Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

MaxLogSize

+
+ +

Examples

+ +
    +MaxLogSize 1048576
    +MaxLogSize 1m
    +MaxLogSize 0
    +
+ +

Description

+ +

The MaxLogSize directive controls the maximum size of each +log file. Once a log file reaches or exceeds the maximum size it is closed +and renamed to filename.O. This allows you to rotate the logs +automatically. The default size is 1048576 bytes (1MB). + +

Setting the maximum size to 0 disables log rotation. + + +

MaxRequestSize

+
+ +

Examples

+ +
    +MaxRequestSize 10485760
    +MaxRequestSize 10m
    +MaxRequestSize 0
    +
+ +

Description

+ +

The MaxRequestSize directive controls the maximum size of +print files, IPP requests, and HTML form data in HTTP POST requests. The +default limit is 0 which disables the limit check. + +

Also see the identical +LimitRequestBody directive. + + +

Order

+
+ +

Examples

+ +
    +Order Allow,Deny
    +Order Deny,Allow
    +
+ +

Description

+ +

The Order directive defines the default access control. +The following values are supported: + +

    + +
  • Allow,Deny - Allow requests from all + systems except for those listed in a Deny + directive. + +
  • Deny,Allow - Allow requests only from + those listed in an Allow directive. + +
+ +

The Order directive must appear inside a +Location directive. + + +

PageLog

+
+ +

Examples

+ +
    +PageLog /var/log/cups/page_log
    +PageLog /var/log/cups/page_log-%s
    +PageLog syslog
    +
+ +

Description

+ +

The PageLog directive sets the name of the page log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default page log file is /var/log/cups/page_log. + +

The server name can be included in the filename by using +%s in the name. + +

The special name "syslog" can be used to send the page information +to the system log instead of a plain file. + + +

Port

+
+ +

Examples

+ +
    +Port 631
    +Port 80
    +
+ +

Description

+ +

The Port directive specifies a port to listen on. +Multiple Port lines can be specified to listen on multiple +ports. The default port is 631. + + +

PreserveJobHistory

+
+ +

Examples

+ +
    +PreserveJobHistory On
    +PreserveJobHistory Off
    +
+ +

Description

+ +

The PreserveJobHistory directive controls whether +the history of completed, cancelled, or aborted print jobs is stored +on disk. + +

A value of On (the default) preserves job information +until the administrator purges it with the cancel +command. + +

A value of Off removes the job information as soon as +each job is completed, cancelled, or aborted. + + +

PreserveJobFiles

+
+ +

Examples

+ +
    +PreserveJobFiles On
    +PreserveJobFiles Off
    +
+ +

Description

+ +

The PreserveJobFiles directive controls whether the +document files of completed, cancelled, or aborted print jobs are +stored on disk. + +

A value of On preserves job files until the +administrator purges them with the cancel command. Jobs +can be restarted (and reprinted) as desired until they are purged. + +

A value of Off (the default) removes the job files as +soon as each job is completed, cancelled, or aborted. + + +

Printcap

+
+ +

Examples

+ +
    +Printcap
    +Printcap /etc/printcap
    +Printcap /etc/printers.conf
    +
+ +

Description

+ +

The Printcap directive controls whether or not a +printcap file is automatically generated and updated with a list +of available printers. If specified with no value, then no +printcap file will be generated. The default is to generate a +file named /etc/printcap. + +

When a filename is specified (e.g. /etc/printcap), the +printcap file is written whenever a printer is added or removed. The +printcap file can then be used by applications that are hardcoded to +look at the printcap file for the available printers. + + +

PrintcapFormat

+
+ +

Examples

+ +
    +PrintcapFormat BSD
    +PrintcapFormat Solaris
    +
+ +

Description

+ +

The PrintcapFormat directive controls the output +format of the printcap file. The default is to generate a BSD +printcap file. + + +

RemoteRoot

+
+ +

Examples

+ +
    +RemoteRoot remroot
    +RemoteRoot root
    +
+ +

Description

+ +

The RemoteRoot directive sets the username for +unauthenticated root requests from remote hosts. The default +username is remroot. Setting RemoteRoot +to root effectively disables this security mechanism. + + +

RequestRoot

+
+ +

Examples

+ +
    +RequestRoot /var/spool/cups
    +RequestRoot /foo/bar/spool/cups
    +
+ +

Description

+ +

The RequestRoot directive sets the directory for +incoming IPP requests and HTML forms. If an absolute path is not +provided then it is assumed to be relative to the +ServerRoot directory. The +default request directory is /var/spool/cups. + + +

RIPCache

+
+ +

Examples

+ +
    +RIPCache 8m
    +RIPCache 1g
    +RIPCache 2048k
    +
+ +

Description

+ +

The RIPCache directive sets the size of the memory +cache used by Raster Image Processor ("RIP") filters such as +imagetoraster and pstoraster. The size can +be suffixed with a "k" for kilobytes, "m" for megabytes, or +"g" for gigabytes. The default cache size is "8m", or 8 megabytes. + + +

RunAsUser

+
+ +

Examples

+ +
    +RunAsUser Yes
    +RunAsUser No
    +
+ +

Description

+ +

The RunAsUser directive controls whether the +scheduler runs as the unpriviledged user account (usually lp). +The default is No which leaves the scheduler running as +the root user. + +

Note: Running as a non-priviledged user may prevent +LPD and locally connected printers from working due to +permission problems. The lpd backend will +automatically use a non-priviledged mode that is not 100% +compliant with RFC 1179. The parallel, +serial, and usb backends will need +write access to the corresponding device files. + + +

ServerAdmin

+
+ +

Examples

+ +
    +ServerAdmin user@host
    +ServerAdmin root@foo.bar.com
    +
+ +

Description

+ +

The ServerAdmin directive identifies the email address for the +administrator on the system. By default the administrator email address is +root@server, where server is the server name. + + +

ServerBin

+
+ +

Examples

+ +
    +ServerBin /usr/lib/cups
    +ServerBin /foo/bar/lib/cups
    +
+ +

Description

+ +

The ServerBin directive sets the directory for +server-run executables. If an absolute path is not provided then it is +assumed to be relative to the +ServerRoot directory. The +default executable directory is /usr/lib/cups or +/usr/lib32/cups (IRIX 6.5). + + +

ServerCertificate

+
+ +

Examples

+ +
    +ServerCertificate /etc/cups/ssl/server.crt
    +
+ +

Description

+ +

The ServerCertificate directive specifies the +location of the SSL certificate file used by the server when +negotiating encrypted connections. The certificate must not be +encrypted (password protected) since the scheduler normally runs +in the background and will be unable to ask for a password. +The default certificate file is /etc/cups/ssl/server.crt. + + +

ServerKey

+
+ +

Examples

+ +
    +ServerKey /etc/cups/ssl/server.key
    +
+ +

Description

+ +

The ServerKey directive specifies the location +of the SSL private key file used by the server when negotiating +encrypted connections. The default key file is +/etc/cups/ssl/server.crt. + + +

ServerName

+
+ +

Examples

+ +
    +ServerName foo.domain.com
    +ServerName myserver.domain.com
    +
+ +

Description

+ +

The ServerName directive specifies the hostname that is +reported to clients. By default the server name is the hostname. + + +

ServerRoot

+
+ +

Examples

+ +
    +ServerRoot /etc/cups
    +ServerRoot /foo/bar/cups
    +
+ +

Description

+ +

The ServerRoot directive specifies the absolute path to +the server configuration and state files. It is also used to resolve +relative paths in the cupsd.conf file. The default server +directory is /etc/cups. + + +

SSLListen

+
+ +

Examples

+ +
    +SSLListen 127.0.0.1:443
    +SSLListen 192.0.2.1:443
    +
+ +

Description

+ +

The SSLListen directive specifies a network +address and port to listen for secure connections. Multiple +SSLListen directives can be provided to listen on +multiple addresses. + +

The SSLListen directive is similar to the +SSLPort directive but allows +you to restrict access to specific interfaces or networks. + + +

SSLPort

+
+ +

Examples

+ +
    +SSLPort 443
    +
+ +

Description

+ +

The SSLPort directive specifies a port to listen +on for secure connections. Multiple SSLPort lines +can be specified to listen on multiple ports. + + +

SystemGroup

+
+ +

Examples

+ +
    +SystemGroup sys
    +SystemGroup system
    +SystemGroup root
    +
+ +

Description

+ +

The SystemGroup directive specifies the system +administration group for System authentication. More +information can be found later in this chapter in +"Printing System Security". + + +

TempDir

+
+ +

Examples

+ +
    +TempDir /var/tmp
    +TempDir /foo/bar/tmp
    +
+ +

Description

+ +

The TempDir directive specifies an absolute path for +the directory to use for temporary files. The default directory is +/var/tmp. + +

Temporary directories must be world-writable and should have the +"sticky" permission bit enabled so that other users cannot delete +filter temporary files. The following commands will create an +appropriate temporary directory called /foo/bar/tmp: + +

    +mkdir /foo/bar/tmp ENTER
    +chmod a+rwxt /foo/bar/tmp ENTER
    +
+ + +

Timeout

+
+ +

Examples

+ +
    +Timeout 300
    +Timeout 90
    +
+ +

Description

+ +

The Timeout directive controls the amount of time to +wait before an active HTTP or IPP request times out. The default +timeout is 300 seconds. + + +

User

+
+ +

Examples

+ +
    +User lp
    +User guest
    +
+ +

Description

+ +

The User directive specifies the UNIX user that +filter and CGI programs run as. The default user is lp. + + +

Printing System Security

+ +

CUPS provides support for address, certificate, and password (Basic +and Digest) based authentication and access control. Certificate and +password authentication provide ways to limit access to individual +people or groups. + +

Address based access control allows you to limit access to specific +systems, networks, or domains. While this does not provide authentication, +it does allow you to limit the potential users of your system efficiently. + +

CUPS maintains a list of locations that have access control and/or +authentication enabled. Locations are specified using the +Location directive: + +

+ +

Locations generally follow the directory structure of the +DocumentRoot directory, however +CUPS does have several virtual locations for administration, classes, jobs, +and printers: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LocationDescription
/adminThe path for all administration operations.
/classesThe path for all classes.
/classes/nameThe resource for class name.
/jobsThe path for all jobs.
/jobs/idThe resource for job id.
/printersThe path for all printers.
/printers/nameThe path for printer name.
/printers/name.ppdThe PPD file path for printer name.
+ +

Authentication Using Certificates

+ +

CUPS supports a local certificate-based authentication scheme that +can be used in place of Basic or Digest +authentication by clients connecting through the localhost +interface. Certificate authentication is not supported or allowed from +clients on any other interface. + +

Certificates are 128-bit random numbers that refer to an internal +authentication record in the server. A client connecting via the +localhost interface sends a request with an +authorization header of: + +

    +Authorization: Local 0123456789ABCDEF0123456789ABCDEF
    +
+ +

The server then looks up the local certificate and authenticates +using the username associated with it. + +

Certificates are generated by the server automatically and stored in +the /etc/cups/certs directory using the process ID of the +CGI program started by the server. Certificate files are only readable +by the User and +Group defined in the +cupsd.conf file. When the CGI program ends the certificate +is removed and invalidated automatically. + +

The special file /etc/cups/certs/0 defines the root +certificate which can be used by any client running as the super-user +or another user that is part of the group defined by the +SystemGroup directive. The +root certificate is automatically regenerated every 5 minutes. + +

Using Basic Authentication

+ +

Basic authentication uses UNIX users and passwords to authenticate +access to resources such as printers and classes, and to limit access +to administrative functions. + +

+ + + +
+ NOTE: + +

Basic authentication sends the username and password Base64 + encoded from the client to the server, so it offers no + protection against eavesdropping. This means that a malicious + user can monitor network packets and discover valid users and + passwords that could result in a serious compromise in network + security. Use Basic authentication with extreme care. +

+ +

The CUPS implementation of Basic authentication does not allow access +through user accounts without a password. If you try to authenticate +using an account without a password, your access will be immediately +blocked. + +

Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked. + +

+ + + +
+ NOTE: + +

The root user is considered by CUPS to be a member of every + group. +

+ + +

Use the AuthType directive to enable Basic authentication: + +

    +AuthType Basic
    +
+ + +

Using Digest Authentication

+ +

Digest authentication uses users and passwords defined in the +/etc/cups/passwd.md5 file to authenticate access to +resources such as printers and classes, and to limit access to +administrative functions. + +

+ + + +
+ NOTE: + +

Unlike Basic authentication, Digest passes the MD5 sum + (basically a complicated checksum) of the username and password + instead of the strings themselves. Also, Digest authentication + does not use the UNIX password file, so if an attacker does + discover the original password it is less likely to result in a + serious security problem so long as you use a different UNIX + password than the corresponding Digest password. + +

The current CUPS implementation of Digest authentication + uses the client's hostname or IP address for the "nonce" value. + The nonce value is an additional string added to the username + and password to make guessing the password more difficult. The + server checks that the nonce value matches the client's hostname + or address and rejects the MD5 sum if it doesn't. Future versions + of CUPS will support Digest "session" authentication which adds + the request data to the MD5 sum, providing even better + authentication and security. + +

Digest authentication does not guarantee that an attacker + cannot gain unauthorized access, but it is safer than Basic + authentication and should be used in place of Basic + authentication whenever possible. Support for Digest + authentication in web browsers is not yet universally + available. +

+ + +

The lppasswd(1) command is used to add, change, or +remove accounts from the passwd.md5 file. To add a +user to the default system group, type: + +

    +lppasswd -a user ENTER
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
+ + +

Once added, a user can change his/her password by typing: + +

    +lppasswd ENTER
    +Old password: (password) ENTER [password is not echoed]
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
+ + +

To remove a user from the password file, type: + +

    +lppasswd -x user ENTER
    +
+ +

Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked. + +

+ + + +
+ NOTE: + +

The root user is considered by CUPS to be a member of every + group. +

+ +

Use the AuthType directive to enable Digest authentication: + +

    +AuthType Digest
    +
+ +

System and Group Authentication

+ +

The AuthClass directive controls +the level of authentication to perform. System and +Group authentication extend the normal user-based authentication +to require membership in a UNIX group. For System authentication +each user must belong to the sys, system, or +root group; the actual group depends on the operating system. + +

For Group authentication each user must belong to the +group named by the AuthGroupName +directive: + +

    +<Location /path>
    +AuthType Digest
    +AuthClass Group
    +AuthGroupName mygroup
    +</Location>
    +
+ +

The named group must be a valid UNIX user group, usually defined in the +/etc/group or /etc/netgroup files. Additionally, when +using Digest authentication you need to create user accounts with the named +group: + +

    +lppasswd -g mygroup -a user ENTER
    +Password: (password) ENTER [password is not echoed]
    +Password again: (password) ENTER [password is not echoed]
    +
+ + +

Printer Accounting

+ +

ESP Print Pro maintains a log of all accesses, errors, and +pages that are printed. The log files are normally stored in the +/var/log/cups directory. You can change this by +editing the /etc/cups/cupsd.conf configuration file. + +

The access_log File

+ +

The access_log file lists each HTTP resource that is accessed +by a web browser or CUPS/IPP client. Each line is in the so-called "Common +Log Format" used by many web servers and web reporting tools: + +

    +host group user date-time \"method resource version\" status bytes
    +
    +127.0.0.1 - - [20/May/1999:19:20:29 +0000] "POST /admin/ HTTP/1.1" 401 0
    +127.0.0.1 - mike [20/May/1999:19:20:31 +0000] "POST /admin/ HTTP/1.1" 200 0
    +
+ +

The host field will normally only be an IP address unless you +have enabled the HostNameLookups +directive in the cupsd.conf file. + +

The group field always contains "-" in CUPS. + +

The user field is the authenticated username of the requesting user. +If no username and password is supplied for the request then this field +contains "-". + +

The date-time field is the date and time of the request in local time +and is in the format: + +

    +[DD/MON/YYYY:HH:MM:SS +ZZZZ]
    +
+ +

where ZZZZ is the timezone offset in hours and minutes from Greenwich +Mean Time (a.k.a. GMT a.k.a. ZULU.) + +

The method field is the HTTP method used ("GET", "PUT", "POST", etc.) + +

The resource field is the filename of the requested resource. + +

The version field is the HTTP specification version used by the +client. For CUPS clients this will always be "HTTP/1.1". + +

The status field contains the HTTP result status of the +request. Usually it is "200", but other HTTP status codes are possible. +For example, 401 is the "unauthorized access" status in the example +above. + +

The bytes field contains the number of bytes in the request. +For POST requests the bytes field contains the number of bytes +that was received from the client. + +

The error_log File

+ +

The error_log file lists messages from the scheduler (errors, +warnings, etc.): + +

    +level date-time message
    +
    +I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.
    +
+ +

The level field contains the type of message: + +

    + +
  • E - An error occurred. + +
  • W - The server was unable to perform some action. + +
  • I - Informational message. + +
  • D - Debugging message. + +
+ +

The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

The message fields contains a free-form textual message. + +

The page_log File

+ +

The page_log file lists each page that is sent to a printer. +Each line contains the following information: + +

    +printer user job-id date-time page-number num-copies job-billing
    +
    +DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0 acme-123
    +
+ +

The printer field contains the name of the printer that +printed the page. If you send a job to a printer class, this field will +contain the name of the printer that was assigned the job. + +

The user field contains the name of the user (the IPP +requesting-user-name attribute) that submitted this file for +printing. + +

The job-id field contains the job number of the page being printed. +Job numbers are reset to 1 whenever the CUPS server is started, so don't depend +on this number being unique! + +

The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

The page-number and num-pages fields contain the page number +and number of copies being printed of that page. For printer that can not +produce copies on their own, the num-pages field will always be 1. + +

The job-billing field contains a copy of the +job-billing attribute provided with the IPP +create-job or print-job requests or "-" if none +was provided. + + +

File Typing and Filtering

+ +

CUPS provides a MIME-based file typing and filtering mechanism to +convert files to a printable format for each printer. On startup the +CUPS server reads MIME database files from the /etc/cups +directory (or a directory specified by the +ServerRoot directive) to build +a file type and conversion database in memory. These database files are +plain ASCII text and can be edited with your favorite text editor. + +

The mime.types and mime.convs files define the +standard file types and filters that are available on the system. + +

mime.types

+ +

The mime.types file defines the known file types. Each line +of the file starts with the MIME type and may be followed by one or +more file type recognition rules. For example, the +text/html file type is defined as: + +

    +text/html       html htm \
    +                printable(0,1024) + \
    +                (string(0,"<HTML>") string(0,"<!DOCTYPE"))
    +
+ +

The first two rules say that any file with an extension of +.html or .htm is a HTML file. The third rule +says that any file whose first 1024 characters are printable text and +starts with the strings <HTML> or +<!DOCTYPE is a HTML file as well. + +

The first two rules deal solely with the name of the file being +typed. This is useful when the original filename is known, however for +print files the server doesn't have a filename to work with. The third +rule takes care of this possibility and automatically figures out the +file type based upon the contents of the file instead. + +

The available tests are: + +

    + +
  • ( expr ) - Parenthesis for expression grouping + +
  • + - Logical AND + +
  • , or whitespace - Logical OR + +
  • ! - Logical NOT + +
  • match("pattern") - Pattern match on filename + +
  • extension - Pattern match on "*.extension" + +
  • ascii(offset,length) - True if bytes are valid + printable ASCII (CR, NL, TAB, BS, 32-126) + +
  • printable(offset,length) - True if bytes are + printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254) + +
  • string(offset,"string") - True if bytes are + identical to string + +
  • contains(offset,range,"string") - True if the + range of bytes contains the string + +
  • char(offset,value) - True if byte is identical + +
  • short(offset,value) - True if 16-bit integer + is identical (network or "big-endian" byte order) + +
  • int(offset,value) - True if 32-bit integer is + identical (network or "big-endian" byte order) + +
  • locale("string") - True if current locale + matches string + +
+ +

All numeric values can be in decimal (123), octal (0123), or hexadecimal +(0x123) as desired. + + +

Strings can be in quotes, all by themselves, as a string +of hexadecimal values, or some combination: + +

    +"string"
    +'string'
    +string
    +<737472696e67>
    +<7374>ring
    +
+ +

As shown in the text/html example, rules can continue on +multiple lines using the backslash (\) character. A more complex example is +the image/jpeg rules: + +

    +image/jpeg      jpeg jpg jpe string(0,<FFD8FF>) &&\
    +                (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
    +                 char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
    +                 char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
    +                 char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
    +
+ +

This rule states that any file with an extension of +.jpeg, .jpg, or .jpe is a JPEG file. +In addition, any file starting with the hexadecimal string +<FFD8FF> (JPEG Start-Of-Image) followed by a +character between and including 0xe0 and 0xef +(JPEG APPn markers) is also a JPEG file. + +

mime.convs

+ +

The mime.convs file defines all of the filter programs that +are known to the system. Each line consists of: + +

    +source destination cost program
    +
    +text/plain application/postscript 50 texttops
    +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster
    +image/* application/vnd.cups-postscript 50 imagetops
    +image/* application/vnd.cups-raster 50 imagetoraster
    +
+ +

The source field is a MIME type, optionally using a wildcard for +the super-type or sub-type (e.g. "text/plain", "image/*", "*/postscript"). + +

The destination field is a MIME type defined in the +mime.types file. + +

The cost field defines a relative cost for the filtering +operation from 1 to 100. The cost is used to choose between two +different sets of filters when converting a file. For example, to convert +from image/jpeg to application/vnd.cups-raster, +you could use the imagetops and pstoraster +filters for a total cost of 100, or the imagetoraster filter +for a total cost of 50. + +

The program field defines the filter program to run; the +special program "-" can be used to make two file types equivalent. The +program must accept the standard filter arguments and environment +variables described in the CUPS Interface Design Description and CUPS +Software Programmers Manual: + +

    +program job user title options [filename]
    +
+ +

If specified, the filename argument defines a file to read +when filtering, otherwise the filter must read from the standard input. +All filtered output must go to the standard output. + + +

Adding Filetypes and Filters

+ +

Adding a new file type or filter is fairly straight-forward. Rather +than adding the new type and filter to the mime.types and +mime.convs files which are overwritten when you upgrade to a +new version of CUPS, you simple need to create new files with +.types and .convs extensions in the +/etc/cups directory. We recommend that you use the product +or format name, e.g.: + +

    +myproduct.types
    +myproduct.convs
    +
+ +

If you are providing a filter for a common file format or printer, +add the company or author name: + +

    +acme-msword.types
    +acme.msword.convs
    +
+ +

This will help to prevent name collisions if you install many +different file types and filters. + +

Once you choose the names for these files, create them using your +favorite text editor as described earlier in this chapter. Once you +have created the files, restart the cupsd process as +described earlier in "Restarting the CUPS Server". + +

Printer Drivers and PPD Files

+ +

Most CUPS printer drivers utilize one or more printer-specific filters +and a PPD file for each printer model. Printer driver filters are registered +via the PPD file using cupsFilter attributes: + +

    +*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
    +
+ +

The filter is specified using the source file type only; the destination +file type is assumed to be printer/name - suitable for sending +to the printer. + +

Writing Your Own Filter or Printer Driver

+ +

CUPS supports an unlimited number of file formats and filters, and can +handle any printer. If you'd like to write a filter or printer driver for +your favorite file format or printer, consult the CUPS Software Programmers +Manual for step-by-step instructions. + + +

7 - Printing with Other Systems

+ +

This chapter describes how to print from client systems that use the +LPD, Mac OS, or Windows printing protocols. + +

The Basics

+ +

CUPS is based on the IPP protocol, so any system that supports IPP +can send jobs to and receive jobs from CUPS automatically. However, not +all systems support IPP yet. This chapter will show you how to connect +these systems to your CUPS server, either to accept jobs from your +server for printing, or to send jobs to your server. + +

Printing from LPD Clients

+ +

CUPS supports limited functionality for LPD-based clients. With LPD you can +print files to specific printers, list the queue status, and so forth. However, +the automatic client configuration and printer options are not supported by +the LPD protocol, so you must manually configure each client for the printers +it needs to access. + +

The cups-lpd(8) program provides support for LPD clients. +To enable LPD support on your server, edit the /etc/inetd.conf +file and add a line reading: + +

    +printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
    +
+ +

The path to the cups-lpd may vary depending on your +installation. + +

Once you have added this line, send the inetd(8) process +a HUP signal or reboot the system: + +

    +killall -HUP inetd ENTER [IRIX and some versions of Linux]
    +kill -HUP pid ENTER [Others]
    +reboot ENTER [For all systems if the HUP signal fails]
    +
+ +

Printing to LPD Servers

+ +

CUPS provides the lpd backend for printing to LPD-based +servers and printers. Use a device URI of lpd://server/name +to print to a printer on an LPD server, where server +is the hostname or IP address of the server and name is +the queue name. + +

Microsoft Windows NT provides an LPD service under the name "TCP/IP +Printing Services". To enable LPD printing on NT, open the "Services" +control panel, select the "TCP/IP Printing Services" service, and click +on the "Start" button. Any shared printer will then be available via +the LPD protocol. + +

Printing from Mac OS Clients

+ +

CUPS does not provide Mac OS support directly. However, there are several +free and commercial software packages that do. + +

Columbia Appletalk Package (CAP)

+ +

Because the CAP LaserWriter server (lwsrv(8)) does +not support specification of PPD files, we do not recommend that you +use CAP with CUPS. However, you can run the lpsrv program +for limited printing with the command: + +

    +lwsrv -n "Name" -p printer -a /usr/lib/adicts -f /usr/lib/LW+Fonts
    +
+ +

where Name is the name you want to use when sharing the +printer, and printer is the name of the CUPS print queue. + + +

XINET KA/Spool

+ +

To use your system as a print server for Mac OS clients, +configure each printer using a papserver(8) in the +/usr/adm/appletalk/services file, specifying the +corresponding PPD file in the /etc/cups/ppd directory for +each printer. For a printer named MyPrinter the entry +would look like: + +

    +/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
    +"Printer Description" MyPrinter
    +
+ +
+ + + +
+ NOTE: + +

Enter the text above on a single line without the backslash (\) + character. +

+ +

NetATalk

+ +

To use your system as a print server for Mac OS clients, +configure each printer in the papd.conf file, specifying the +corresponding PPD file in the /etc/cups/ppd directory for +each printer. For a printer named MyPrinter the entry +would look like: + +

    +Printer Description:MyPrinter@MyServer:\
    +        :pr=|/usr/bin/lp -d MyPrinter:\
    +        :op=daemon:\
    +        :pd=/etc/cups/ppd/MyPrinter.ppd:
    +
+ + + +

Printing to Mac OS Servers

+ +

CUPS currently does not provide a backend to communicate with a Mac OS +server. However, you can write and install a short shell script +in the /usr/lib/cups/backend directory that sends a print file +using the appropriate command. The following is a short script that will +run the papif command provided with CAP. + +

After copying this script to /usr/lib/cups/backend/cap, +specify a device URI of cap://server/printer to use this +backend with a print queue. + + +

    +
    +"/usr/lib/cups/backend/cap"
    +#!/bin/sh
    +#
    +# Usage: cap job user title copies options [filename]
    +#
    +
    +# No arguments means show available devices...
    +
    +if test ${#argv} = 0; then
    +	echo "network cap \"Unknown\" \"Mac OS Printer via CAP\""
    +	exit 0
    +fi
    +
    +# Collect arguments...
    +
    +user=$2
    +copies=$4
    +
    +if test ${#argv} = 5; then
    +	# Get print file from stdin; copies have already been handled...
    +	file=/var/tmp/$$.prn
    +	copies=1
    +	cat > $file
    +else
    +	# Print file is on command-line...
    +	file=$6
    +fi
    +
    +# Create a dummy cap.printers file for this printer based
    +# upon a device URI of "cap://server/printer"...
    +
    +echo $PRINTER/$DEVICE_URI | \
    +	awk -F/ '{print $1 "=" $5 ":LaserWriter@" $4}' > /var/tmp/$$.cap
    +
    +CAPPRINTERS=/var/tmp/$$.cap; export CAPPRINTERS
    +
    +# Send the file to the printer, once for each copy. This assumes that you
    +# have properly initialized the cap.printers file...
    +
    +while [ $copies -gt 0 ]; do
    +	papif -n $user < $file
    +
    +        copies=`expr $copies - 1`
    +done
    +
    +# Remove any temporary files...
    +if test ${#argv} = 5; then
    +	/bin/rm -f $file
    +fi
    +
    +/bin/rm -f /var/tmp/$$.cap
    +
    +exit 0
    +
+ + +

Printing from Windows Clients

+ +

While CUPS does not provide Windows support directly, the free +SAMBA software package does. SAMBA version 2.0.6 is the first release +of SAMBA that supports CUPS. You can download SAMBA from: + +

+ +

To configure SAMBA for CUPS, edit the smb.conf file and +replace the existing printing commands and options with the line: + +

    +printing = cups
    +
+ +

That's all there is to it! Remote users will now be able to browse and +print to printers on your system. + +

Printing to Windows Servers

+ +

CUPS can print to Windows servers in one of two ways. The first way uses +the LPD protocol on the CUPS system and the "TCP/IP Printing Services" on +the Windows system. You can find out more about this configuration in the +LPD section earlier in this chapter. + +

The second way is through the Microsoft Server Message Block ("SMB") +protocol. Support for this protocol is provided with the free SAMBA +software package. You can download SAMBA from: + +

+ +

To configure CUPS for SAMBA, run the following command: + +

    +ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER
    +
+ +

The smbspool(1) program is provided with SAMBA starting +with SAMBA 2.0.6. Once you have made the link you can configure your +printers with one of the following device URIs: + +

    +smb://workgroup/server/sharename
    +smb://server/sharename
    +smb://user:pass@workgroup/server/sharename
    +smb://user:pass@server/sharename
    +
+ +

The workgroup name need only be specified if your +system is using a different workgroup. The user:pass +strings are required when printing to Windows NT servers or to shares +with passwords enabled under Windows 95 and 98. + + +

A - Software License Agreement

+ + + + +

B - Common Network Settings

+ +

This appendix covers many of the popular TCP/IP network interfaces +and printer servers available on the market today. + +

Configuring a Network Interface

+ +

When you first install a network printer or print server on your +LAN, you need to set the Internet Protocol ("IP") address. On most +higher-end "workgroup" printers, you can set the address through the +printer control panel. However, in most cases you will want to assign +the addresses remotely from your workstation. This makes administration +a bit easier and avoids assigning duplicate addresses accidentally. + +

To setup your printer or print server for remote address assignment, +you'll need the Ethernet Media Access Control ("MAC") address, also +sometimes called a node address, and the IP address you want to use for +the device. The Ethernet MAC address can often be found on the printer +test page or bottom of the print server. + + +

Configuring the IP Address Using ARP

+ +

The easiest way to set the IP address of a network device is to use +the arp(8) command. The arp sends an Address +Resolution Protocol ("ARP") packet to the specified Ethernet MAC address, +setting the network device's IP address: + +

    +arp -s ip-address ethernet-address ENTER
    +arp -s host.domain.com 08:00:69:00:12:34 ENTER
    +arp -s 192.0.2.2 08:00:69:00:12:34 ENTER
    +
+ +

Configuring the IP Address Using RARP

+ +

The most flexible way to remotely assign IP addresses under UNIX +is through the Reverse Address Resolution Protocol ("RARP"). RARP +allows a network device to request an IP address using its Ethernet +MAC address, and one or more RARP servers on the network will +respond with an ARP packet with the IP address the device can use. + +

RARP should be used when you have to manage many printers or print +servers, or when you have a network device that does not remember its +IP address after a power cycle. If you just have a single printer or +print server, the arp command is the way to go. + +

Some UNIX operating systems use a program called +rarpd(8) to manage RARP. Others, like Linux, support this +protocol in the kernel. For systems that provide the rarpd +program you will need to start it before RARP lookups will work: + +

    +rarpd ENTER
    +
+ +

Under IRIX you can enable this functionality by default using: + +

    +chkconfig rarpd on ENTER
    +
+ +

Both the rarpd program and kernel RARP support read a +list of Ethernet and IP addresses from the file /etc/ethers. +Each line contains the Ethernet address (colon delimited) followed by +an IP address or hostname like: + +

    +08:00:69:00:12:34 myprinter.mydomain.com
    +08:00:69:00:12:34 192.0.2.2
    +
+ +

Add a line to this file and cycle the power on the printer or print +server to set its address. + + +

Configuring the IP Address Using BOOTP

+ +

The BOOTP protocol is used when you need to provide additional information +such as the location of a configuration file to the network interface. Using +the standard bootpd(8) program supplied with UNIX you simply need to +add a line to the /etc/bootptab file; for IRIX: + +

    +myprinter 08:00:69:00:12:34 192.0.2.2 myprinter.boot
    +
+ + +

Newer versions of bootpd use a different format: + +

    +myprinter:ha=080069001234:ip=192.0.2.2:t144=myprinter.boot
    +
+ +

The myprinter.boot file resides in the /usr/local/boot +directory by default. If you do not need to provide a boot file you may leave +the last part of the line blank. + + +

+ + + +
+ NOTE: + +

Some versions of UNIX do not enable the BOOTP service by + default. The /etc/inetd.conf usually contains a + line for the BOOTP service that can be uncommented if + needed. +

+ +

Verifying the Printer Connection

+ +

To test that the IP address has been successfully assigned and that the +printer is properly connected to your LAN, type: + +

    +ping ip-address ENTER
    +
+ +

If the connection is working properly you will see something like: + +

    +ping myprinter ENTER
    +PING myprinter (192.0.2.2): 56 data bytes
    +64 bytes from 192.0.2.2: icmp_seq=0 ttl=15 time=5 ms
    +64 bytes from 192.0.2.2: icmp_seq=1 ttl=15 time=3 ms
    +64 bytes from 192.0.2.2: icmp_seq=2 ttl=15 time=3 ms
    +64 bytes from 192.0.2.2: icmp_seq=3 ttl=15 time=3 ms
    +
+ +

If not, verify that the printer or print server is connected to the +LAN, it is powered on, the LAN cabling is good, and the IP address is +set correctly. You can usually see the current IP address and network +status by printing a configuration or test page on the device. + + +

Common Network Interface Settings

+ +

Once you have set the IP address you can access the printer or print +server using the ipp, lpd, or +socket backends. The following is a list of common network +interfaces and printer servers and the settings you should use with +CUPS: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Model/ManufacturerDevice URI(s)
Apple LaserWriterlpd://address/PASSTHRU
Axis w/o IPP
+ (see directions)
socket://address:9100
+ socket://address:9101
+ socket://address:9102
Axis w/IPPipp://address/LPT1
+ ipp://address/LPT2
+ ipp://address/COM1
Castelle LANpressTMlpd://address/pr1
+ lpd://address/pr2
+ lpd://address/pr3
DPI NETPrintlpd://address/pr1
+ lpd://address/pr2
+ lpd://address/pr3
EFI® Fiery® RIPlpd://address/print
EPSON® Multiprotocol Ethernet Interface Boardsocket://address
Extended System ExtendNETlpd://address/pr1
+ lpd://address/pr2
+ lpd://address/pr3
Hewlett Packard JetDirect w/o IPPsocket://address:9100
+ socket://address:9101
+ socket://address:9102
Hewlett Packard JetDirect w/IPPipp://address/ipp
+ ipp://address/ipp/port1
+ ipp://address/ipp/port2
+ ipp://address/ipp/port3
Intel® NetportExpress XL, PRO/100lpd://address/LPT1_PASSTHRU
+ lpd://address/LPT2_PASSTHRU
+ lpd://address/COM1_PASSTHRU
LexmarkTM MarkNetlpd://address/ps
Linksys EtherFast®
+ (see directions)
socket://address:4010
+ socket://address:4020
+ socket://address:4030
Kodak®lpd://address/ps
QMS® CrownNetTMlpd://address/ps
Tektronix® PhaserShareTMsocket://address:9100
XEROX® 4512 NIClpd://address/PORT1
XEROX® XNIClpd://address/PASSTHRU
XEROX® (most others)socket://address:5503
+ +

Configuring Axis Print Servers

+ +

The Axis print servers can be configured using ARP, RARP, or BOOTP. +However, on models that do not provide IPP support an additional step +must be performed to configure the TCP/IP portion of the print server +for use with CUPS. + + +

Each print server contains a configuration file named +config that contains a list of network parameters used by +the server. To modify this file you must first download it from the +print server using the ftp(1) program: + +

    +ftp ip-address ENTER
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root ENTER
    +331 User name ok, need password
    +Password: pass ENTER (this is not echoed)
    +230 User logged in
    +ftp> get config ENTER
    +local: config remote: config
    +200 PORT command successful.
    +150 Opening data connection for config (192,0,2,2),
    +(mode ascii).
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
+ + +

Next, edit the file with your favorite text editor and locate the +lines beginning with: + +

    +RTN_OPT.     : YES
    +RTEL_PR1.    : 0
    +RTEL_PR2.    : 0
    +RTEL_PR3.    : 0
    +RTEL_PR4.    : 0
    +RTEL_PR5.    : 0
    +RTEL_PR6.    : 0
    +RTEL_PR7.    : 0
    +RTEL_PR8.    : 0
    +
+ + +Change the RTN_OPT line to read: + +
    +RTN_OPT.     : NO
    +
+ + +

This disables the Reverse TELNET protocol and enables the standard +TELNET protocol on the print server. Next, assign a port number for +each parallel and serial port on the server as follows: + +

    +RTEL_PR1.    : 9100
    +RTEL_PR2.    : 9101
    +RTEL_PR3.    : 9102
    +RTEL_PR4.    : 9103
    +RTEL_PR5.    : 9104
    +RTEL_PR6.    : 9105
    +RTEL_PR7.    : 9106
    +RTEL_PR8.    : 9107
    +
+ + +

This essentially makes the Axis print server look like a Hewlett +Packard JetDirect EX print server. Save the file and then upload the +new config file using the ftp command: + +

    +ftp ip-address ENTER
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root ENTER
    +331 User name ok, need password
    +Password: pass ENTER (this is not echoed)
    +230 User logged in
    +ftp> put config CONFIG ENTER
    +local: config remote: CONFIG
    +200 PORT command successful.
    +150 Opening data connection for config (192,0,2,2), (mode ascii).
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> get hardreset ENTER
    +local: hardreset remote: hardreset
    +200 PORT command successful.
    +421 Axis NPS ### hard reset, closing connection.
    +ftp> quit ENTER
    +221 Goodbye.
    +
+ +

Your Axis print server is now ready for use! + +

Configuring Linksys Print Servers

+ +

The Linksys print servers can be configured using ARP, RARP, or +BOOTP. Like older Axis print servers, an additional step must be +performed to configure the TCP/IP portion of the print server for use +with CUPS. + + +

Each print server contains a configuration file named +CONFIG that contains a list of network parameters used by +the server. To modify this file you must first download it from the +print server using the ftp(1) program: + +

    +ftp -n ip-address ENTER
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> get CONFIG ENTER
    +local: CONFIG remote: CONFIG
    +200 Command OK.
    +150 Open ASCII Mode Connection.
    +WARNING! 68 bare linefeeds received in ASCII mode
    +File may not have transferred correctly.
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
+ + +

Next, edit the file with your favorite text editor and locate the +lines beginning with: + +

    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P1
    +0140 L3_PROUT:P1
    +
+ +

Change the port number for +each parallel and serial port on the server as follows: + +

    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P2
    +0140 L3_PROUT:P3
    +
+ + +

This maps each virtual printer with a physical port. Save the file and then upload the +new CONFIG file using the ftp command: + +

    +ftp -n ip-address ENTER
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> put CONFIG ENTER
    +local: CONFIG remote: CONFIG
    +200 Command OK.
    +150 Open ASCII Mode Connection.
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit ENTER
    +221 Goodbye.
    +
+ +

Your Linksys print server is now ready for use! + + +

C - Printer Drivers

+ +

This appendix lists the printer drivers that are provided with CUPS. + +

Printer Drivers

+ +

CUPS includes the following printer drivers: + +

+ +

EPSON 9-pin Dot Matrix

+ +

The EPSON 9-pin Dot Matrix driver (epson9.ppd) supports +9-pin dot matrix printers that implement the ESC/P command set. It +provides 60x72, 120x72, and 240x72 DPI output in black only. + +

EPSON 24-pin Dot Matrix

+ +

The EPSON 24-pin Dot Matrix driver (epson9.ppd) supports +24-pin dot matrix printers that implement the ESC/P command set. It +provides 120x180, 180x180, 360x180, and 360x360 DPI output in black +only. + +

EPSON Stylus Color

+ +

The EPSON Stylus Color driver (stcolor.ppd) supports +EPSON Stylus Color printers that implement the ESC/P2 command set. It +provides 180, 360, and 720 DPI output in black and color (CMYK). + +

EPSON Stylus Photo

+ +

The EPSON Stylus Photo driver (stphoto.ppd) supports +EPSON Stylus Photo printers that implement the ESC/P2 command set. It +provides 180, 360, and 720 DPI output in black and color (CMYKcm). + +

HP DeskJet

+ +

The HP DeskJet driver (deskjet.ppd) supports HP DeskJet +printers that implement the PCL command set. It provides 150, 300, and +600 DPI output in black and color (CMYK). + +

The DeskJet printers that implement the HP-PPA command set (720C, +722C, 820C, and 1100C) are not supported due to a complete lack +of documentation and support from Hewlett Packard. + +

The duplexer provided with the HP DeskJet 900 series printers is also +not supported for similar reasons. + +

HP LaserJet

+ +

The HP LaserJet driver (laserjet.ppd) supports HP +LaserJet printers that implement the PCL command set. It provides 150, +300, and 600 DPI output in black only and supports the duplexer if +installed. + +

LaserJet printers that do not implement PCL (3100, 3150) are not +supported due to a complete lack of documentation and support from +Hewlett Packard. + + +

D - List of Files

+ +

This appendix lists the files and directories that are installed for +the Common UNIX Printing System. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathnameDescription
/etc/cups/certs/The location of authentication certificate files for local + HTTP clients.
/etc/cups/classes.confThe printer classes configuration file for the scheduler.
/etc/cups/cupsd.confThe scheduler configuration file.
/etc/cups/interfaces/The location of System V interface scripts for printers.
/etc/cups/mime.convsThe list of standard file filters included with ESP Print Pro.
/etc/cups/mime.typesThe list of recognized file types for ESP Print Pro.
/etc/cups/ppd/The location of PostScript Printer Description ("PPD") files for + printers.
/etc/cups/printers.confThe printer configuration file for the scheduler.
/usr/bin/cancelThe System V cancel job(s) command.
/usr/bin/disableThe System V disable printer command.
/usr/bin/enableThe System V enable printer command.
/usr/bin/lpThe System V print command.
/usr/bin/lpoptionsSets user-defined printing options and defaults.
/usr/bin/lppasswdAdds, changes, or removes Digest password accounts.
/usr/bin/lpqThe Berkeley status command.
/usr/bin/lprThe Berkeley print command.
/usr/bin/lprmThe Berkeley cancel job(s) command.
/usr/bin/lpstatThe System V status command.
/usr/include/cups/CUPS API header files.
/usr/lib32/libcups.a
+ /usr/lib32/libcupsimage.a
Static libraries (IRIX 6.5)
/usr/lib/libcups.a
+ /usr/lib/libcupsimage.a
Static libraries (all others)
/usr/lib/libcups.sl.2
+ /usr/lib/libcupsimage.sl.2
Shared libraries (HP-UX)
/usr/lib32/libcups.so.2
+ /usr/lib32/libcupsimage.so.2
Shared libraries (IRIX 6.5)
/usr/lib/libcups.so.2
+ /usr/lib/libcupsimage.so.2
Shared libraries (all others)
/usr/lib/cups/backend/Backends for various types of printer connections.
/usr/lib/cups/cgi-bin/CGI programs for the scheduler.
/usr/lib/cups/daemon/Daemons for polling and LPD support.
/usr/lib/cups/filter/Filters for various types of files.
/usr/lib/locale/The location of language-specific message files. (System V)
/usr/lib/nls/msg/The location of language-specific message files. (Compaq Tru64 UNIX)
/usr/share/locale/The location of language-specific message files. (Linux, *BSD)
/usr/sbin/acceptThe accept-jobs command.
/usr/sbin/cupsdThe CUPS print scheduler.
/usr/sbin/lpadminThe System V printer administration tool.
/usr/sbin/lpcThe Berkeley printer administration tool.
/usr/sbin/lpinfoThe get-devices and get-ppds command.
/usr/sbin/lpmoveThe move-jobs command.
/usr/sbin/rejectThe reject-jobs command.
/usr/share/catman/a_man/
+ /usr/share/catman/u_man/
Man pages (IRIX)
/usr/share/man/Man pages (Compaq Tru64 UNIX, HP-UX, Solaris)
/usr/man/Man pages (all others)
/usr/share/cups/data/The location of filter data files.
/usr/share/cups/data/testprint.psThe PostScript test page file.
/usr/share/cups/fonts/The location of PostScript fonts for the PostScript RIP.
/usr/share/cups/model/The location of PostScript Printer Description ("PPD") files and + interface scripts that may be used to setup a printer queue.
/usr/share/cups/pstoraster/Other PostScript RIP initialization files.
/usr/share/cups/pstoraster/FontmapThe font mapping file (converts filenames to fontnames)
/usr/share/cups/templates/The location of HTML template files for the web interfaces.
/usr/share/doc/cups/Documentation and web page data for the scheduler.
/var/log/cups/The location of scheduler log files.
/var/spool/cups/The location of print files waiting to be printed.
+ + +

E - Troubleshooting Common Problems

+ +

This appendix covers some of the common problems first-time users +encounter when installing and configuring CUPS. + +

Commercial support for CUPS is available from Easy Software Products. +For more information please contact us at: + +

+ +

My Applications Don't See the Available Printers

+ +

Many applications read the /etc/printcap file to +get a list of available printers. + +

The default CUPS configuration does not create the +/etc/printcap file automatically. To enable automatic +creation and updating of this file, use the +Printcap directive described in +Chapter 6, "Printing System Management". + +

CUPS Doesn't Recognize My Username or Password!

+ +

CUPS will ask you for a UNIX username and password when you perform +printer administration tasks remotely or via a web browser. The default +configuration requires that you use the root username and +the corresponding password to authenticate the request. + +

CUPS does not allow you to authenticate an administration request +with an account that has no password for security reasons. If you do +not have a password on your root account then you won't be +able to add printers remotely or via the web interface! + + +

To disable password authentication you need to edit the +/etc/cups/cupsd.conf file and comment out the +lines reading: + +

    +AuthType Basic
    +AuthClass System
    +
+ +for the /admin location. Then restart the CUPS server as +described in Chapter 8, "Printing System +Management". + +
+ + + +
+ NOTE: + +

Disabling password checks will allow any local user to + change your printer and class configuration, but remote + administration from another machine will still not be allowed. +

+ +

I Can't Do Administration Tasks from Another Machine!

+ +

The default CUPS configuration limits administration to the local +machine. To open up access, edit the /etc/cups/cupsd.conf +and comment out the lines reading: + +

    +Order deny,allow
    +Deny from all
    +Allow from 127.0.0.1
    +
+ +for the /admin location. Then restart the CUPS server as +described in Chapter 8, "Printing System +Management". + +
+ + + +
+ NOTE: + +

Allowing administration access from all hosts is a potential + security risk. Please read Chapter + 6, "Printing System Management" for a description of these + risks and ways to minimize them. +

+ + +

I Can't Do Administration Tasks from My Web Browser!

+ +

This problem is usually caused by: + +

    + +
  1. not specifying the correct password for the + root account. + +
  2. accessing the CUPS server using the hostname or IP + address of the server without enabling remote access for + administration functions. This can be corrected by following + the instructions in the "I Can't Do + Administration Tasks from Another Machine!" section earlier + in this appendix. + +
  3. not setting a password on the root account. CUPS will not + authenticate a user account that does not have a password for + security reasons. + +
  4. authenticating using an account other than root, but the + account you are using is not a member of the system group. + +
  5. configuring CUPS to use Digest authentication, but + your web browser does not support Digest authentication. + +
+ +

Connection Refused Messages

+ +

Under normal circumstances, "connection refused" messages for a +networked printer should be expected from time to time. Most network +interfaces only allow a single connection to be made at any given time +(one job at a time) and will refuse access to all other systems while +the first connection is active. CUPS automatically retries the +connection once every 30 seconds. + +

If the problem persists and you are unable to print any jobs to the printer, +verify that another machine is not maintaining a connection with the printer, +and that you have selected the proper port or printer name for the printer. + +

Also, most external print servers will refuse connections if the connected +printer is turned off or is off-line. Verify that the affected printer is +turned on and is online. + +

Write Error Messages

+ +

If you get "write error" messages on a printer queue the printer +interface (usually a Hewlett Packard JetDirect interface) has timed out +and reset the network connection from your workstation. + +

The error is caused by that startup delay between the initial setup +of the printer or plotter and the first page of print data that is +sent. + + +

To correct the problem, change the idle timeout on the interface to at least +180 seconds or 3 minutes. To change the timeout on a Hewlett Packard +JetDirect interface, type: + +

    +telnet ip-address ENTER
    +
    +Trying ip-address...
    +Connected to ip-address.
    +Escape character is `^]'.
    +
    +Please type [Return] two times, to initialize telnet configuration
    +For HELP type "?"
    +> idle-timeout: 180 ENTER
    +> quit ENTER
    +
+ + + diff --git a/doc/sdd.html b/doc/sdd.html new file mode 100644 index 0000000000..2c9f95bf40 --- /dev/null +++ b/doc/sdd.html @@ -0,0 +1,596 @@ + + + + CUPS Software Design Description + + + + + + + +

+

CUPS Software Design Description


+CUPS-SDD-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Design Overview + +A Glossary + +
+

1 Scope

+

1.1 Identification

+ This software design description document provides general information + on the architecture and coding of the Common UNIX Printing System + ("CUPS") Version 1.1. +

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+ This software design description document is organized into the + following sections: +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Design Overview
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Design Overview

+ CUPS is composed of 9 software sub-systems that operate together to + perform common printing tasks: +
    +
  • Backends
  • +
  • Berkeley Commands
  • +
  • CGI
  • +
  • CUPS Application Programmers Interface
  • +
  • CUPS Imaging Library
  • +
  • Daemons
  • +
  • Filters
  • +
  • Scheduler
  • +
  • System V Commands
  • +
+

3.1 Backends

+ The backends implement communications over a number of different +interfaces. All backends are called with a common set of arguments: +
    +
  • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, ipp://hostname/resource +).
  • +
  • Job Identifier - the job identifier for this job (integer).
  • +
  • User Name - the user associated with this job (name string).
  • +
  • Title - the title/job-name associated with this job (name string).
  • +
  • Copies - the number of copies required (integer).
  • +
  • Options - the options associated with this job (space separated + option strings).
  • +
  • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input.
  • +
+

Backends are named using the scheme of the URI, so a URI of +"ipp://hostname/resource" would be processed by the "ipp" backend.

+

3.1.1 ipp

+

The ipp backend sends the specified job to a network printer or host +using the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host.

+

3.1.2 lpd

+

The lpd backend sends the specified job to a network printer or host +using the Line Printer Daemon protocol. The URI is of the form:

+
    +
    lpd://hostname/queue
    +
    +
+

3.1.3 parallel

+

The parallel backend sends the specified job to a local printer +connected via the specified parallel port device. The URI is of the +form:

+
    +
    parallel:/dev/file
    +
    +
+

3.1.4 serial

+

The serial backend sends the specified job to a local printer +connected via the specified serial port device. The URI is of the +form:

+
    +
    serial:/dev/file?option[+option+...]
    +
    +
+ The options can be any combination of the following: +
    +
  • baud=rate - Sets the baud rate for the device.
  • +
  • bits=7 or 8 - Sets the number of data bits.
  • +
  • parity=even - Sets even parity checking.
  • +
  • parity=odd - Sets odd parity checking.
  • +
  • parity=none - Turns parity checking off.
  • +
  • flow=dtrdsr - Turns DTR/DSR (hardware) flow + control on.
  • +
  • flow=hard - Turns RTS/CTS (hardware) flow +control on.
  • +
  • flow=none - Turns flow control off.
  • +
  • flow=rtscts - Turns RTS/CTS (hardware) flow +control on.
  • +
  • flow=xonxoff - Turns XON/XOFF (software) flow +control on.
  • +
+

3.1.5 socket

+

The socket backend sends the specified job to a network host using +the AppSocket protocol commonly used by Hewlett-Packard and Tektronix +printers. The URI is of the form:

+
    +
    socket://hostname[:port]
    +
    +
+ The default port number is 9100. +

3.1.6 usb

+

The usb backend sends the specified job to a local printer connected +via the specified usb port device. The URI is of the form:

+
    +
    usb:/dev/file
    +
    +
+

3.2 Berkeley Commands

+

The Berkeley commands provide a simple command-line interface to +CUPS to submit and control print jobs. It is provided for compatibility +with existing software that is hardcoded to use the Berkeley commands.

+

3.2.1 lpc

+ The lpc command allows users and administrators to check the status +and control print queues. The version provided with CUPS supports the +following commands: +
    +
  • quit - Quits the lpc command.
  • +
  • status - Shows the status of printers and jobs in the queue.
  • +
+

3.2.2 lpq

+

The lpq command shows the current queue status.

+

3.2.3 lpr

+

The lpr command submits a job for printing. The CUPS version of lpr +silently ignores the "i", "t", "m", "h", and "s" options.

+

3.2.4 lprm

+

The lprm removes one or more print jobs.

+

3.3 CGI

+

The Common Gateway Interface (CGI) programs provide a web-based +status interface to monitor the status of printers, classes, and jobs. +Each of the CGIs utilize HTML template files that can be customized to +provide alternate appearances.

+

3.3.1 admin.cgi

+

The admin CGI provides administration interfaces for printers and +classes. The user can add, modify, delete, start, stop, and configure +printers and classes using "wizard" interfaces.

+

3.3.2 classes.cgi

+

The classes CGI lists the available printer classes and any pending +jobs for the class. The user can click on individual classes to limit +the display and click on jobs to see the job status.

+

3.3.3 jobs.cgi

+

The jobs CGI lists the queued print jobs in order of priority. The +list can be limited by printer or job.

+

3.3.4 printers.cgi

+

The printers CGI lists the available printer queues and any pending +jobs for the printer. The user can click on individual printers to +limit the display and click on jobs to see the job status.

+

3.4 CUPS Application Programmers Interface

+

The CUPS Application Programmers Interface ("API") provides common +convenience, HTTP, IPP, language, and PPD functions used by the CUPS +software.

+

3.4.1 Convenience Functions

+

Convenience functions are provided to submit an IPP request, send a +print file, cancel a job, get a list of available printers, get a list +of available classes, get the default printer or class, get the default +server name, get the local username, and get a password string.

+

3.4.2 HTTP Functions

+

The HTTP functions provide functions to connect to HTTP servers, +issue requests, read data from a server, and write data to a server.

+

3.4.3 IPP Functions

+

The IPP function provide functions to manage IPP request data and +attributes, read IPP responses from a server, and write IPP requests to +a server.

+

3.4.4 Language Functions

+

The language functions provide a standard interface for retrieving +common textual messages for a particular locale and determining the +correct encoding (e.g. US ASCII, UTF-8, ISO-8859-1, etc.)

+

3.4.5 PPD Functions

+

The PostScript Printer Description functions manage PPD files, +select options, check for option conflicts, and emit selected options +in the correct order.

+

3.5 CUPS Imaging Library

+

The CUPS imaging library provides colorspace conversion, color +management, image management, scaling, image file, and raster functions +used by the CUPS raster filters.

+

3.5.1 Colorspace Conversion Functions

+

The colorspace conversion functions handle conversion of grayscale +and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces.

+

3.5.2 Color Management Functions

+

The color management functions handle gamut mapping and density +correction. These are integrated with the colorspace conversion +functions so that colorspace conversion and color management are +processed in a single step.

+

3.5.3 Image Management Functions

+

The image management functions manage a tiled image database that is +swapped to/from disk as needed.

+

3.5.4 Scaling Functions

+

The scaling functions provide image scaling services using +nearest-neighbor sampling and bilinear interpolation as appropriate.

+

3.5.5 Image File Functions

+

The image file functions handle loading of all image file formats.

+

3.5.6 Raster Functions

+

The raster functions manage streams of CUPS raster data (described +in the Interface Design Document) used by non-PostScript printer +drivers and raster filters.

+

3.6 Daemons

+

The daemons provide additional network functions for the scheduler. +Currently only two daemons are provided with CUPS.

+

3.6.1 Line Printer Daemon

+

The line printer daemon provides remote LPD client support and is +run by the inetd(8) daemon as needed.

+

3.6.2 Polling Daemon

+

The polling daemon is used to poll a remote server for a list of +available printers and provide it to the scheduler for addition. A +separate polling daemon is run by the scheduler for every remote system +listed for polling in the scheduler configuration file.

+

3.7 Filters

+

The filters implement file conversion services for CUPS. All filters +are called with a common set of arguments:

+
    +
  • Printer name - the name of the destination printer (name string).
  • +
  • Job Identifier - the job identifier for this job (integer).
  • +
  • User Name - the user associated with this job (name string).
  • +
  • Title - the title/job-name associated with this job (name string).
  • +
  • Copies - the number of copies required (integer).
  • +
  • Options - the options associated with this job (space separated + option strings).
  • +
  • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard + input.
  • +
+

Filters are added to the MIME conversion data file and implement all +necessary conversions from one file type to another.

+

3.7.1 hpgltops

+

The hpgltops filter converts HP-GL/2 files into PostScript.

+

3.7.2 imagetops

+

The imagetops filter converts image files into PostScript.

+

3.7.3 imagetoraster

+

The imagetoraster filter converts image files into CUPS raster data.

+

3.7.4 pdftops

+

The pdftops filter converts PDF files into PostScript.

+

3.7.5 pstops

+

The pstops filter inserts printer-specific commands from PPD files +and performs page filtering as requested by the user.

+

3.7.6 pstoraster

+

The pstoraster filter converts PostScript program data into CUPS +raster data.

+

3.7.7 rastertoepson

+

The rastertoepson filter handles converting CUPS raster data to +ESC/P and supports both color and black-and-white printers.

+

3.7.8 rastertohp

+

The rastertohp filter handles converting CUPS raster data to HP-PCL +and supports both color and black-and-white printers.

+

3.7.9 texttops

+

The texttops filter converts text files into PostScript.

+

3.8 Scheduler

+

The scheduler is a fully-functional HTTP/1.1 and IPP/1.1 server that +manages the printers, classes, and jobs in the system. It also handles +a simple broadcast-based directory service so that remote print queues +and classes can be accessed transparently from the local system.

+

3.8.1 Authorization

+

The authorization module is responsible for performing access +control and authentication for all HTTP and IPP requests entering the +system.

+

3.8.2 Classes

+

The classes module is responsible for managing printer classes in +the system. Each class is a collection of local and/or remote printers. + The classes module also reads and writes the classes configuration +file.

+

3.8.3 Client

+

The client module is responsible for all HTTP client communications. + It handles listening on selected interfaces, accepting connections +from prospective clients, processing incoming HTTP requests, and +sending HTTP responses to those requests. The client module also is +responsible for executing the external CGI programs as needed to +support web-based printer, class, and job status monitoring and +administration.

+

Once authorized, all IPP requests are sent to the IPP module.

+

3.8.4 Configuration

+

The configuration module is responsible for reading the CUPS +configuration file and initializing the appropriate data structures and +values. The configuration module also stops CUPS services before +reading the configuration file and restarts them after the +configuration file has been read.

+

3.8.5 Devices

+

The devices module is responsible for managing the list of available +devices for the CUPS-Get-Devices operation.

+

3.8.6 Directory Services

+

The directory services module sends and recieves printer state +information over a broadcast socket. Remote printers and classes are +automatically added to or removed from the local printer and class +lists as needed.

+

The directory services module can only recieve printer state +information over a single UDP port, however it can broadcast to +multiple addresses and ports as needed.

+

3.8.7 IPP

+

The IPP module handles IPP requests and acts accordingly. URI +validation is also performed here, as a client can post IPP data to any +URI on the server which might sidestep the access control or +authentication of the HTTP server.

+

3.8.8 Jobs

+

The jobs module manages print jobs, starts filter and backend +processes for jobs to be printed, and monitors status messages from +those filters and backends.

+

3.8.9 Logging

+

The logging module manages the access, error, and page log files +that are generated by the scheduler.

+

3.8.10 Main

+

The main module is responsible for timing out and dispatching input +and output for client connections. It also watches for incoming +SIGHUP and SIGCHLD signals, reloads the server +configuration files as needed, and handles child process errors and +exits.

+

3.8.11 MIME

+

The Multimedia Internet Mail Exchange module manages a MIME type and +conversion database that supports file typing by extension and content +and least-cost file filtering from a source to a destination file type.

+

3.8.12 PPDs

+

The PPDs module is responsible for managing the list of available +PPD files for the CUPS-Get-PPDs operation.

+

3.8.13 Printers

+

The printers module is responsible for managing printers and PPD +files in the system. The printers module also reads and writes the +printers configuration file.

+

3.9 System V Commands

+

The System V commands provide a robust command-line interface to +CUPS to submit and control printers and jobs.

+

3.9.1 accept

+

The accept command tells the scheduler to accept new jobs for +specific printers.

+

3.9.2 cancel

+

The cancel command tells the scheduler to cancel one or more jobs +that are queued for printing.

+

3.9.3 disable

+

The disable command tells the scheduler to stop printing jobs on the +specified printers.

+

3.9.4 enable

+

The enable command tells the scheduler to start printing jobs on the +specified printers.

+

3.9.5 lp

+

The lp command submits submits files for printing. Unlike the +standard System V lp command, a single CUPS lp command will generate a +separate job ID for each file that is printed. Also, the Solaris "f", +"H", "P", "S", and "y" options are silently ignored.

+

3.9.6 lpadmin

+

The lpadmin command manages printer queues and classes. The Solaris +"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", +"s", "t", and "u" options are not supported, and new options "P" (PPD +file) and "E" (enable and accept) are provided to configure +CUPS-specific features.

+

3.9.7 lpinfo

+

The lpinfo command lists the available PPD files or devices as +selected by the user.

+

3.9.8 lpmove

+

The lpmove command moves a print job to a new destination.

+

3.9.9 lpoptions

+

The lpoptions command manages user-defined printers and options.

+

3.9.10 lpstat

+

The lpstat command lists printers, classes, and jobs as requested by +the user.

+

3.9.11 reject

+

The reject command tells the scheduler not to accept new jobs for +specific printers.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/sdd.pdf b/doc/sdd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b801309fdb0b903df252f5a9d3d08411e38e3c48 GIT binary patch literal 64440 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

wIIb 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 n5hx+yvxU2gkWs3hjC@J7#XY=K{w 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 literal 0 Hc-jL100001 diff --git a/doc/sdd.shtml b/doc/sdd.shtml new file mode 100644 index 0000000000..6ae0c958f6 --- /dev/null +++ b/doc/sdd.shtml @@ -0,0 +1,564 @@ + + + + + + CUPS Software Design Description + + + +

Scope

+ +

Identification

+ +This software design description document provides general information +on the architecture and coding of the Common UNIX Printing System +("CUPS") Version 1.1. + + + +

Document Overview

+ +This software design description document is organized into the +following sections: + +
    + +
  • 1 - Scope + +
  • 2 - References + +
  • 3 - Design Overview + +
  • A - Glossary + +
+ + + +

Design Overview

+ +CUPS is composed of 9 software sub-systems that operate together to +perform common printing tasks: + +
    + +
  • Backends + +
  • Berkeley Commands + +
  • CGI + +
  • CUPS Application Programmers Interface + +
  • CUPS Imaging Library + +
  • Daemons + +
  • Filters + +
  • Scheduler + +
  • System V Commands + +
+ +

Backends

+ +The backends implement communications over a number of different interfaces. +All backends are called with a common set of arguments: + +
    + +
  • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, + ipp://hostname/resource). + +
  • Job Identifier - the job identifier for this job (integer). + +
  • User Name - the user associated with this job (name string). + +
  • Title - the title/job-name associated with this job (name string). + +
  • Copies - the number of copies required (integer). + +
  • Options - the options associated with this job (space separated + option strings). + +
  • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input. + +
+ +

Backends are named using the scheme of the URI, so a URI of +"ipp://hostname/resource" would be processed by the "ipp" backend. + +

ipp

+ +

The ipp backend sends the specified job to a network printer or host using +the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host. + +

lpd

+ +

The lpd backend sends the specified job to a network printer or host using +the Line Printer Daemon protocol. The URI is of the form: + +

    lpd://hostname/queue
    +
+ +

parallel

+ +

The parallel backend sends the specified job to a local printer connected +via the specified parallel port device. The URI is of the form: + +

    parallel:/dev/file
    +
+ +

serial

+ +

The serial backend sends the specified job to a local printer connected +via the specified serial port device. The URI is of the form: + +

    serial:/dev/file?option[+option+...]
    +
+ +The options can be any combination of the following: + +
    + +
  • baud=rate - Sets the baud rate for the device. + +
  • bits=7 or 8 - Sets the number of data bits. + +
  • parity=even - Sets even parity checking. + +
  • parity=odd - Sets odd parity checking. + +
  • parity=none - Turns parity checking off. + +
  • flow=dtrdsr - Turns DTR/DSR (hardware) flow + control on. + +
  • flow=hard - Turns RTS/CTS + (hardware) flow control on. + +
  • flow=none - Turns flow control off. + +
  • flow=rtscts - Turns RTS/CTS + (hardware) flow control on. + +
  • flow=xonxoff - Turns XON/XOFF + (software) flow control on. + +
+ +

socket

+ +

The socket backend sends the specified job to a network host using the +AppSocket protocol commonly used by Hewlett-Packard and Tektronix +printers. The URI is of the form: + +

    socket://hostname[:port]
    +
+ +The default port number is 9100. + +

usb

+ +

The usb backend sends the specified job to a local printer connected +via the specified usb port device. The URI is of the form: + +

    usb:/dev/file
    +
+ +

Berkeley Commands

+ +

The Berkeley commands provide a simple command-line interface to CUPS +to submit and control print jobs. It is provided for compatibility with +existing software that is hardcoded to use the Berkeley commands. + +

lpc

+ +The lpc command allows users and administrators to check the status and +control print queues. The version provided with CUPS supports the following +commands: + +
    + +
  • quit - Quits the lpc command. + +
  • status - Shows the status of printers and jobs in the queue. + +
+ +

lpq

+ +

The lpq command shows the current queue status. + +

lpr

+ +

The lpr command submits a job for printing. The CUPS version of lpr silently +ignores the "i", "t", "m", "h", and "s" options. + +

lprm

+ +

The lprm removes one or more print jobs. + +

CGI

+ +

The Common Gateway Interface (CGI) programs provide a web-based +status interface to monitor the status of printers, classes, and jobs. +Each of the CGIs utilize HTML template files that can be customized to +provide alternate appearances. + +

admin.cgi

+ +

The admin CGI provides administration interfaces for printers and +classes. The user can add, modify, delete, start, stop, and configure +printers and classes using "wizard" interfaces. + +

classes.cgi

+ +

The classes CGI lists the available printer classes and any pending +jobs for the class. The user can click on individual classes to limit +the display and click on jobs to see the job status. + +

jobs.cgi

+ +

The jobs CGI lists the queued print jobs in order of priority. The +list can be limited by printer or job. + +

printers.cgi

+ +

The printers CGI lists the available printer queues and any pending +jobs for the printer. The user can click on individual printers to +limit the display and click on jobs to see the job status. + +

CUPS Application Programmers Interface

+ +

The CUPS Application Programmers Interface ("API") provides common +convenience, HTTP, IPP, language, and PPD functions used by the CUPS +software. + +

Convenience Functions

+ +

Convenience functions are provided to submit an IPP request, send a +print file, cancel a job, get a list of available printers, get a list +of available classes, get the default printer or class, get the default +server name, get the local username, and get a password string. + +

HTTP Functions

+ +

The HTTP functions provide functions to connect to HTTP servers, +issue requests, read data from a server, and write data to a server. + +

IPP Functions

+ +

The IPP function provide functions to manage IPP request data and +attributes, read IPP responses from a server, and write IPP requests to +a server. + +

Language Functions

+ +

The language functions provide a standard interface for retrieving +common textual messages for a particular locale and determining the +correct encoding (e.g. US ASCII, UTF-8, ISO-8859-1, etc.) + +

PPD Functions

+ +

The PostScript Printer Description functions manage PPD files, +select options, check for option conflicts, and emit selected options +in the correct order. + +

CUPS Imaging Library

+ +

The CUPS imaging library provides colorspace conversion, color +management, image management, scaling, image file, and raster functions +used by the CUPS raster filters. + +

Colorspace Conversion Functions

+ +

The colorspace conversion functions handle conversion of grayscale +and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces. + +

Color Management Functions

+ +

The color management functions handle gamut mapping and density +correction. These are integrated with the colorspace conversion +functions so that colorspace conversion and color management are +processed in a single step. + +

Image Management Functions

+ +

The image management functions manage a tiled image database that is +swapped to/from disk as needed. + +

Scaling Functions

+ +

The scaling functions provide image scaling services using +nearest-neighbor sampling and bilinear interpolation as appropriate. + +

Image File Functions

+ +

The image file functions handle loading of all image file formats. + +

Raster Functions

+ +

The raster functions manage streams of CUPS raster data (described +in the Interface Design Document) used by non-PostScript printer +drivers and raster filters. + +

Daemons

+ +

The daemons provide additional network functions for the scheduler. +Currently only two daemons are provided with CUPS. + +

Line Printer Daemon

+ +

The line printer daemon provides remote LPD client support and is +run by the inetd(8) daemon as needed. + +

Polling Daemon

+ +

The polling daemon is used to poll a remote server for a list of +available printers and provide it to the scheduler for addition. A +separate polling daemon is run by the scheduler for every remote +system listed for polling in the scheduler configuration file. + +

Filters

+ +

The filters implement file conversion services for CUPS. All filters +are called with a common set of arguments: + +

    + +
  • Printer name - the name of the destination printer (name string). + +
  • Job Identifier - the job identifier for this job (integer). + +
  • User Name - the user associated with this job (name string). + +
  • Title - the title/job-name associated with this job (name string). + +
  • Copies - the number of copies required (integer). + +
  • Options - the options associated with this job (space separated + option strings). + +
  • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard + input. + +
+ +

Filters are added to the MIME conversion data file and implement all +necessary conversions from one file type to another. + +

hpgltops

+ +

The hpgltops filter converts HP-GL/2 files into PostScript. + +

imagetops

+ +

The imagetops filter converts image files into PostScript. + +

imagetoraster

+ +

The imagetoraster filter converts image files into CUPS raster data. + +

pdftops

+ +

The pdftops filter converts PDF files into PostScript. + +

pstops

+ +

The pstops filter inserts printer-specific commands from PPD files and +performs page filtering as requested by the user. + +

pstoraster

+ +

The pstoraster filter converts PostScript program data into CUPS +raster data. + +

rastertoepson

+ +

The rastertoepson filter handles converting CUPS raster data to +ESC/P and supports both color and black-and-white printers. + +

rastertohp

+ +

The rastertohp filter handles converting CUPS raster data to HP-PCL +and supports both color and black-and-white printers. + +

texttops

+ +

The texttops filter converts text files into PostScript. + +

Scheduler

+ +

The scheduler is a fully-functional HTTP/1.1 and IPP/1.1 server that +manages the printers, classes, and jobs in the system. It also handles +a simple broadcast-based directory service so that remote print queues +and classes can be accessed transparently from the local system. + +

Authorization

+ +

The authorization module is responsible for performing access +control and authentication for all HTTP and IPP requests entering the +system. + +

Classes

+ +

The classes module is responsible for managing printer classes in +the system. Each class is a collection of local and/or remote +printers. The classes module also reads and writes the classes +configuration file. + +

Client

+ +

The client module is responsible for all HTTP client +communications. It handles listening on selected interfaces, accepting +connections from prospective clients, processing incoming HTTP +requests, and sending HTTP responses to those requests. The client +module also is responsible for executing the external CGI programs as +needed to support web-based printer, class, and job status monitoring +and administration. + +

Once authorized, all IPP requests are sent to the IPP module. + +

Configuration

+ +

The configuration module is responsible for reading the CUPS +configuration file and initializing the appropriate data structures and +values. The configuration module also stops CUPS services before +reading the configuration file and restarts them after the +configuration file has been read. + +

Devices

+ +

The devices module is responsible for managing the list of available +devices for the CUPS-Get-Devices operation. + +

Directory Services

+ +

The directory services module sends and recieves printer state +information over a broadcast socket. Remote printers and classes are +automatically added to or removed from the local printer and class +lists as needed. + +

The directory services module can only recieve printer state information +over a single UDP port, however it can broadcast to multiple addresses and +ports as needed. + +

IPP

+ +

The IPP module handles IPP requests and acts accordingly. URI +validation is also performed here, as a client can post IPP data to any +URI on the server which might sidestep the access control or +authentication of the HTTP server. + +

Jobs

+ +

The jobs module manages print jobs, starts filter and backend +processes for jobs to be printed, and monitors status messages from +those filters and backends. + +

Logging

+ +

The logging module manages the access, error, and page log files +that are generated by the scheduler. + +

Main

+ +

The main module is responsible for timing out and dispatching input +and output for client connections. It also watches for incoming +SIGHUP and SIGCHLD signals, reloads the +server configuration files as needed, and handles child process errors +and exits. + +

MIME

+ +

The Multimedia Internet Mail Exchange module manages a MIME type and +conversion database that supports file typing by extension and content +and least-cost file filtering from a source to a destination file type. + +

PPDs

+ +

The PPDs module is responsible for managing the list of available +PPD files for the CUPS-Get-PPDs operation. + +

Printers

+ +

The printers module is responsible for managing printers and PPD +files in the system. The printers module also reads and writes the +printers configuration file. + +

System V Commands

+ +

The System V commands provide a robust command-line interface to +CUPS to submit and control printers and jobs. + +

accept

+ +

The accept command tells the scheduler to accept new jobs for specific +printers. + +

cancel

+ +

The cancel command tells the scheduler to cancel one or more jobs that are +queued for printing. + +

disable

+ +

The disable command tells the scheduler to stop printing jobs on the +specified printers. + +

enable

+ +

The enable command tells the scheduler to start printing jobs on the +specified printers. + +

lp

+ +

The lp command submits submits files for printing. Unlike the standard +System V lp command, a single CUPS lp command will generate a separate +job ID for each file that is printed. Also, the Solaris "f", "H", "P", "S", +and "y" options are silently ignored. + +

lpadmin

+ +

The lpadmin command manages printer queues and classes. The Solaris +"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", +"s", "t", and "u" options are not supported, and new options "P" (PPD +file) and "E" (enable and accept) are provided to configure +CUPS-specific features. + +

lpinfo

+ +

The lpinfo command lists the available PPD files or devices as selected +by the user. + +

lpmove

+ +

The lpmove command moves a print job to a new destination. + +

lpoptions

+ +

The lpoptions command manages user-defined printers and options. + +

lpstat

+ +

The lpstat command lists printers, classes, and jobs as requested by the +user. + +

reject

+ +

The reject command tells the scheduler not to accept new jobs for specific +printers. + + + + + diff --git a/doc/spm.html b/doc/spm.html new file mode 100644 index 0000000000..724a715b57 --- /dev/null +++ b/doc/spm.html @@ -0,0 +1,7511 @@ + + + + CUPS Software Programmers Manual + + + + + + + +


+

CUPS Software Programmers Manual


+CUPS-SPM-1.1.7
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - The CUPS API + +3 - Writing Filters + +4 - Writing Printer Drivers + +5 - Writing Backends + +A - Software License Agreement + +B - Constants + +C - Structures + +D - Functions + +
+

Preface

+

This software programmers manual provides software programming +information for the Common UNIX Printing System ("CUPS") Version 1.1.7.

+

System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+ + + +

Document Overview

+

This software programmers manual is organized into the following +sections:

+ +

Notation Conventions

+

Various font and syntax conventions are used in this guide. Examples +and their meanings and uses are explained below: +

+ + + + + + + + + + + + +
Example   Description
 
lpstat +
lpstat(1)
   The names of +commands; the first mention of a command or function in a chapter is +followed by a manual page section number.
 
/var +
/usr/share/cups/data/testprint.ps
    +File and directory names.
 
Request ID is Printer-123 +   Screen output.
 
lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are +written using the period (.) to indicate the decimal point.
+
+ + +

+

Abbreviations

+ The following abbreviations are used throughout this manual: +
    +
    +
    kb
    +
    Kilobytes, or 1024 bytes +
     
    +
    Mb
    +
    Megabytes, or 1048576 bytes +
     
    +
    Gb
    +
    Gigabytes, or 1073741824 bytes +
     
    +
    +
+

Other References

+
    +
    +
    CUPS Software Administrators Manual
    +
    An administration guide for the CUPS software. +
     
    +
    CUPS Software Users Manual
    +
    An end-user guide for using the CUPS software. +
     
    +
    +
+

1 - Printing System Overview

+

This chapter provides an overview of how the Common UNIX Printing +System works.

+

The Printing Problem

+

For years the printing problem has plagued UNIX. Unlike +Microsoft® Windows® or Mac OS, UNIX has no standard interface or system +in place for supporting printers. Among the solutions currently +available, the Berkeley and System V printing systems are the most +prevalent.

+

These printing systems support line printers (text only) or +PostScript printers (text and graphics), and with some coaxing they can +be made to support a full range of printers and file formats. However, +because each varient of the UNIX operating system uses a different +printing system than the next developing printer drivers for a wide +range of printers and operating systems is extremely difficult. That +combined with the limited volume of customers for each UNIX varient has +forced most printer vendors to give up supporting UNIX entirely.

+

CUPS is designed to eliminate the printing problem. One +common printing system can be used by all UNIX varients to support the +printing needs of users. Printer vendors can use its modular filter +interface to develop a single driver program that supports a wide range +of file formats with little or no effort. Since CUPS provides both the +System V and Berkeley printing commands, users (and applications) can +reap the benefits of this new technology with no changes.

+

The Technology

+

CUPS is based upon an emerging Internet standard called the Internet +Printing Protocol. IPP has been embraced by dozens of printer and +printer server manufacturers and is supported by Microsoft Windows +2000.

+

IPP defines a standard protocol for printing as well as managing +print jobs and printer options like media size, resolution, and so +forth. Like all IP-based protocols, IPP can be used locally or over the +Internet to printers hundreds or thousands of miles away. Unlike other +protocols, however, IPP also supports access control, authentication, +and encryption, making it a much more capable and secure printing +solution than older ones.

+

IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") +which is the basis of web servers on the Internet. This allows users to +view documentation, check status information on a printer or server, +and manage their printers, classes, and jobs using their web browser.

+

CUPS provides a complete IPP/1.1 based printing system that provides +Basic, Digest, and local certificate authentication and user, domain, +or IP-based access control. TLS encryption will be available in future +versions of CUPS.

+

Jobs

+

Each file or set of files that is submitted for printing is called a +job. Jobs are identified by a unique number starting at 1 and are +assigned to a particular destination, usually a printer. Jobs can also +have options associated with them such as media size, number of copies, +and priority.

+

Classes

+

CUPS supports collections of printers known as classes. Jobs +sent to a class are forwarded to the first available printer in the +class.

+

Filters

+

Filters allow a user or application to print many types of files +without extra effort. Print jobs sent to a CUPS server are filtered +before sending them to a printer. Some filters convert job files to +different formats that the printer can understand. Others perform page +selection and ordering tasks.

+

CUPS provides filters for printing many types of image files, +HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript +and image file Raster Image Processor ("RIP") filters that convert +PostScript or image files into bitmaps that can be sent to a raster +printer.

+

Backends

+

Backends perform the most important task of all - they send the +filtered print data to the printer.

+

CUPS provides backends for printing over parallel, serial, and USB +ports, and over the network via the IPP, JetDirect (AppSocket), and +Line Printer Daemon ("LPD") protocols. Additional backends are +available in network service packages such as the SMB backend included +with the popular SAMBA software.

+

Backends are also used to determine the available devices. On +startup each backend is asked for a list of devices it supports, and +any information that is available. This allows the parallel backend to +tell CUPS that an EPSON Stylus Color 600 printer is attached to +parallel port 1, for example.

+

Printer Drivers

+

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes sample printer drivers for Hewlett-Packard +LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, +and Stylus Photo printers. While these drivers do not generate optimal +output for the different printer models, they do provide basic printing +and demonstrate how you can write your own printer drivers and +incorporate them into CUPS.

+

Networking

+

Printers and classes on the local system are automatically shared +with other systems on the network. This allows you to setup one system +to print to a printer and use this system as a printer server or spool +host for all of the others. Users may then select a local printer by +name or a remote printer using "name@server".

+

CUPS also provides implicit classes, which are collections of +printers and/or classes with the same name. This allows you to setup +multiple servers pointing to the same physical network printer, for +example, so that you aren't relying on a single system for printing. +Because this also works with printer classes, you can setup multiple +servers and printers and never worry about a single point of failure +unless all of the printers and servers go down!

+

2 - The CUPS API

+

This chapter describes the CUPS Application Programmers Interface +("API").

+

The CUPS API Library

+

The CUPS library provides a whole collection of interfaces needed to +support the internal needs of the CUPS software as well as the needs of +applications, filters, printer drivers, and backends.

+

Unlike the rest of CUPS, the CUPS API library is provided under the +GNU Library General Public License. This means that you can use the +CUPS API library in both proprietary and open-source programs.

+

Programs that use the CUPS API library typically will include the +<cups/cups.h> header file:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +jobid = cupsPrintFile("myprinter", "filename.ps", "title",
    +                      num_options, options);
    +
    +
+

Use the -lcups compiler option when linking to the CUPS +API library:

+
    +
    +cc -o program program.c -lcups ENTER
    +
    +
+

Additional options and libraries may be required depending on the +operating system and the location of the CUPS API library.

+

Detecting the CUPS API Library in GNU Autoconf

+

GNU autoconf is a popular configuration tool used by many programs. +Add the following lines to your configure.in file to check for the +CUPS API library in your configuration script:

+
    +
    +AC_CHECK_LIB(socket,socket,
    +if test "$uname" != "IRIX"; then
    +	LIBS="-lsocket $LIBS"
    +else
    +	echo "Not using -lsocket since you are running IRIX."
    +fi)
    +AC_CHECK_LIB(nsl,gethostbyaddr,
    +if test "$uname" != "IRIX"; then
    +	LIBS="-lnsl $LIBS"
    +else
    +	echo "Not using -lnsl since you are running IRIX."
    +fi)
    +
    +AC_CHECK_LIB(cups,httpConnect)
    +
    +
+

Printing Services

+

The CUPS API library provides some basic printing services for +applications that need to print files.

+

Include Files

+

The include file used by all of these functions is +<cups/cups.h>:

+
    +
    +#include <cups/cups.h>
    +
    +
+

Printing a File

+

The CUPS API provides two functions for printing files. The first is +cupsPrintFile which prints a single named file:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +
    +...
    +
    +jobid = cupsPrintFile("name", "filename", "title", 0, NULL);
    +
    +
+

The name string is the name of the printer or class to +print to. The filename string is the name of the file to +print. The title string is the name of the print job, e.g. +"Acme Word Document".

+

The return value is a unique ID number for the print job or 0 if +there was an error.

+

Printing Multiple Files

+

The second printing function is cupsPrintFiles:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int        jobid;
    +int        num_files;
    +const char *files[100];
    +...
    +
    +jobid = cupsPrintFiles("name", num_files, files, "title", 0, NULL);
    +
    +
+

Instead of passing a filename string as with cupsPrintFile() +, you pass a file count (num_files) and filename pointer +array (files) for each file that you want to print.

+

As with cupsPrintFile(), the return value is a unique +ID for the print job.

+

Cancelling Jobs

+

The cupsCancelJob() function cancels a queued print +job:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +int status;
    +...
    +
    +status = cupsCancelJob("name", jobid);
    +
    +
+

The name string specifies the destination and is used +to determine the server to send the request to. The jobid + value is the integer returned from a previous cupsPrintFile() + or cupsPrintFiles() call.

+

cupsCancelJob() returns 1 if the job was +successfully cancelled and 0 if there was an error.

+

Getting the Available Printers and Classes

+

The cupsGetDests() function can be used to get a list +of the available printers, classes, and instances that a user has +defined:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +...
    +
    +num_dests = cupsGetDests(&dests);
    +
    +
+

Each destination is stored in a cups_dest_t structure +which defines the printer or class name, the instance name (if any), if +it is the default destination, and the default options the user has +defined for the destination:

+
    +
    +typedef struct               /**** Destination ****/
    +{
    +  char          *name,       /* Printer or class name */
    +                *instance;   /* Local instance name or NULL */
    +  int           is_default;  /* Is this printer the default? */
    +  int           num_options; /* Number of options */
    +  cups_option_t *options;    /* Options */
    +} cups_dest_t;
    +
    +
+

The destinations are sorted by name and instance for your +convenience. Once you have the list of available destinations, you can +lookup a specific destination using the cupsGetDest() + function:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *mydest;
    +
    +...
    +
    +mydest = cupsGetDest("name", "instance", num_dests, dests);
    +
    +
+

The name string is the printer or class name. You can +pass a value of NULL to get the default destination.

+

The instance string is the user-defined instance name. +Pass NULL to select the default instance, e.g. "name" +instead of "name/instance".

+

Printing with Options

+

All of the previous printing examples have passed 0 and +NULL for the last two arguments to the cupsPrintFile() + and cupsPrintFiles() functions. These last two arguments +are the number of options and a pointer to the option array:

+
    +
    +int cupsPrintFile(const char *name, const char *filename, const char *title,
    +                  int num_options, cups_option_t *options);
    +int cupsPrintFiles(const char *name, int num_files, const char **files,
    +                   const char *title, int num_options,
    +		   cups_option_t *options);
    +
    +
+

The cups_option_t structure holds each option and its +value. These are converted as needed and passed to the CUPS server when +printing a file.

+

The simplest way of handling options is to use the num_options + and options members of the cups_dest_t + structure described earlier:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int         jobid;
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *mydest;
    +
    +...
    +
    +mydest = cupsGetDest("name", "instance", num_dests, dests);
    +
    +jobid  = cupsPrintFile(mydest->name, "filename", "title",
    +                       mydest->num_options, mydest->options);
    +
    +
+

This effectively uses the options a user has previous selected +without a lot of code.

+

Setting Printer Options

+

Options can also be set by your program using the +cupsAddOption() function:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +num_options = 0;
    +options     = NULL;
    +
    +...
    +
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +
    +
+

The name string is the name of the option, and the +value string is the value for that option.

+

Each call to cupsAddOption() returns the new number of +options. Since adding two options with the same name overwrites the +first value with the second, do not assume that calling +cupsAddOptions() 20 times will result in 20 options.

+

Call cupsFreeOptions once you are done using the +options:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +cupsFreeOptions(num_options, options);
    +
    +
+

Getting Errors

+

If any of the CUPS API printing functions returns an error, the +reason for that error can be found by calling cupsLastError() + and cupsErrorString(). cupsLastError() + returns the last IPP error code that was encountered. +cupsErrorString() converts the error code to a localized message +string suitable for presentation to the user:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +
    +...
    +
    +if (jobid == 0)
    +  puts(cupsErrorString(cupsLastError()));
    +
    +
+

Passwords and Authentication

+

CUPS supports authentication of any request, including submission of +print jobs. The default mechanism for getting the username and password +is to use the login user and a password from the console.

+

To support other types of applications, in particular Graphical User +Interfaces ("GUIs"), the CUPS API provides functions to set the default +username and to register a callback function that returns a password +string.

+

The cupsSetPasswordCB() + function is used to set a password callback in your program. Only one +function can be used at any time.

+

The cupsSetUser() function +sets the current username for authentication. This function can be +called by your password callback function to change the current +username as needed.

+

The following example shows a simple password callback that gets a +username and password from the user:

+
    +
    +#include <cups/cups.h>
    +
    +const char *
    +my_password_cb(const char *prompt)
    +{
    +  char	user[65];
    +
    +
    +  puts(prompt);
    +
    + /* Get a username from the user */
    +  printf("Username: ");
    +  if (fgets(user, sizeof(user), stdin) == NULL)
    +    return (NULL);
    +
    + /* Strip the newline from the string and set the user */
    +  user[strlen(user) - 1] = '\0';
    +
    +  cupsSetUser(user);
    +
    + /* Use getpass() to ask for the password... */
    +  return (getpass("Password: "));
    +}
    +
    +...
    +
    +cupsSetPasswordCB(my_password_cb);
    +
    +
+

Similarly, a GUI interface could display the prompt string in a +window with input fields for the username and password. The username +should probably default to the value of +cupsUser() to make things easier on the user.

+

PPD Services

+

CUPS includes functions to access and manipulate PostScript Printer +Description ("PPD") files that are used with the printer drivers in +CUPS.

+

Each PPD file enumerates the available features provided by a +printer, including conflict information for specific options (e.g. +can't duplex output on envelopes.)

+

Include Files

+

Include the <cups/ppd.h> header file to use the PPD +functions:

+
    +
    +#include <cups/ppd.h>
    +
    +
+

This header file is also included by the <cups/cups.h> + header file.

+

Getting a PPD File for a Printer

+

The cupsGetPPD() function retrieves the PPD file for +the named printer or class:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +const char *filename;
    +
    +filename = cupsGetPPD("name");
    +
    +
+

The name string is the name of the printer or class, +including the remote server name as appropriate (e.g. +"printer@server".)

+

The return value is a pointer to a filename in static storage; this +value is overwritten with each call to cupsGetPPD(). If +the printer or class does not exist, a NULL pointer will +be returned.

+

Loading a PPD File

+

The ppdOpenFile() function "opens" a PPD file and loads +it into memory:

+
    +
    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +ppd = ppdOpenFile("filename");
    +
    +
+

The filename string is the name of the file to load, +such as the value returned by the cupsGetPPD() function.

+

The return value is a pointer to a structure describing the contents +of the PPD file or NULL if the PPD file could not be read.

+

Freeing PPD File Information

+

Once you are done using a PPD file, call the ppdClose() + function to free all memory that has been used:

+
    +
    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +...
    +
    +ppdClose(ppd);
    +
    +
+

The PPD File Structure

+

Each PPD file contains a number of capability attributes, printer +options, and conflict definitions. The page size options also include +the physical margins for the printer and the minimum and maximum sizes +for the printer. All of this information is stored in the +ppd_file_t structure.

+

Capabilities

+

Each PPD file contains a number of informational attributes that +describe the capabilities of the printer. These are provided in the +ppd_file_t structure in the following members: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
accurate_screensint +1 = supports accurate screens
color_deviceint1 = +color device
colorspaceppd_cs_t +Default colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY, PPD_CS_RGB, +PPD_CS_RGBK, PPD_CS_N
contone_onlyint1 = +printer is continuous tone only
num_emulations +
emulations
int +
ppd_emul_t *
Emulations supported by the +printer
flip_duplexint1 = +need to flip odd pages when duplexing
num_fonts +
fonts
int +
char **
The fonts available on the printer.
jcl_begin +
jcl_ps +
jcl_end
char *Job +Control Language commands for PostScript output
landscapeint +Landscape orientation, -90 or 90 degrees
lang_encodingchar * +The character used for the option strings
lang_versionchar * +The language used for the options strings (English, French, etc.)
language_levelint +PostScript language level, 1 to 3
manual_copiesint1 = +Copies are done manually
model_numberint +Driver-specific model number.
patcheschar *Patch +commands to send to the printer
manufacturerchar * +The Manufacturer attribute from the PPD file, if any
modelnamechar *The +ModelName attribute from the PPD file
nicknamechar *The +NickName attribute from the PPD file, if any
productchar *The +Product attribute from the PPD file, if any
shortnicknamechar * +The ShortNickName attribute from the PPD file, if any
throughputintNumber +of pages per minute
ttrasterizerchar * +The TruType font rasterizer (Type42)
variable_sizesint1 += supports variable sizes
+
+

+

Options and Groups

+

PPD files support multiple options, which are stored in +ppd_option_t and ppd_choice_t structures by the PPD +functions.

+

Each option in turn is associated with a group stored in the +ppd_group_t structure. Groups can be specified in the PPD file; +if an option is not associated with a group then it is put in a +"General" or "Extra" group depending on the option.

+

Groups can also have sub-groups; CUPS currently limits the depth of +sub-groups to 1 level to reduce programming complexity.

+

Conflicts

+

PPD files support specification of conflict conditions between +different options. Conflicts are stored in ppd_conflict_t + structures which specify the options that conflict with each other.

+

Page Sizes

+

PPD files specify all of the available pages sizes and the physical +margins associated with them. These sizes are stored in ppd_size_t + structures and are available in the num_sizes and +sizes members of the ppd_file_t structure. You can +lookup a particular page size with the ppdPageWidth(), +ppdPageLength(), and ppdPageSize() functions:

+
    +
    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +ppd_size_t *size;
    +float      width;
    +float      length;
    +
    +...
    +
    +size   = ppdPageSize(ppd, "size");
    +width  = ppdPageWidth(ppd, "size");
    +length = ppdPageLength(ppd, "size");
    +
    +
+

The size string is the named page size option. The +width and length are in points; there are 72 points per inch. The +ppd_size_t structure contains the width, length, and margin +information:

+
    +
    +typedef struct    /**** Page Sizes ****/
    +{
    +  int   marked;   /* Page size selected? */
    +  char  name[41]; /* Media size option */
    +  float width,    /* Width of media in points */
    +        length,   /* Length of media in points */
    +        left,     /* Left printable margin in points */
    +        bottom,   /* Bottom printable margin in points */
    +        right,    /* Right printable margin in points */
    +        top;      /* Top printable margin in points */
    +} ppd_size_t;
    +
    +
+

Custom Page Sizes

+

Besides the standard page sizes listed in a PPD file, some printers +support variable or custom page sizes. If variables_sizes + is non-zero, the custom_min, custom_max, and +custom_margins members of the ppd_file_t structure +define the limits of the variable sizes.

+

To get the resulting media size, use a page size string of +Custom.widthxlength, where width and +length are integer values in points:

+
    +
    +Custom.612x792   [8.5 inches wide, 11 inches long]
    +Custom.1224x792  [17 inches wide, 11 inches long]
    +
    +
+

Marking Options

+

Before marking any user-defined options, call the +ppdMarkDefaults() function to mark the default options from the +PPD file:

+
    +
    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +...
    +
    +ppdMarkDefaults(ppd);
    +
    +
+

Then call the ppdMarkOption() function to mark +individual options:

+
    +
    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +int        conflicts;
    +
    +...
    +
    +conflicts = ppdMarkOption(ppd, "name", "value");
    +
    +
+

The name and value strings choose a +particular option and choice, respectively. The return value is 0 if +there are not conflicts created by the selection.

+

CUPS also provides a convenience function for marking all options in +the cups_option_t structure:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +ppd_file_t    *ppd;
    +int           num_options;
    +cups_option_t *options;
    +int           conflicts;
    +
    +...
    +
    +conflicts = cupsMarkOptions(ppd, num_options, options);
    +
    +
+

The cupsMarkOptions() function also handles mapping the +IPP job template attributes to PPD options. The return value is the +number of conflicts present.

+

Checking for Conflicts

+

The ppdMarkOption() and cupsMarkOptions() + functions return the number of conflicts with the currently marked +options.

+

Call the ppdConflicts() function to get the number of +conflicts after you have marked all of the options:

+
    +
    +#include <cups/cups.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +int        conflicts;
    +
    +...
    +
    +conflicts = ppdConflicts(ppd);
    +
    +
+

The return value is the number of conflicting options, or 0 if there +are no conflicts.

+

3 - Writing Filters

+

This chapter describes how to write a file filter for CUPS.

+

Overview

+

File filters are programs that convert from one or more MIME types +to another type. Filters use a common command-line and environment +interface that allows them to be joined as needed to print files to any +type of printer.

+

Security Considerations

+

Filters are normally run as a non-priviledged user, so the major +security consideration is resource utilization - filters should not +depend on unlimited amounts of memory and disk space.

+

Users and Groups

+

The default CUPS configuration runs filters as user "lp" and group +"other".

+

Temporary Files

+

Temporary files should be created in the directory specified by the +"TMPDIR" environment variable. The +cupsTempFile() function can be used to safely choose +temporary files in this directory.

+

Sending Messages to the User

+

The CUPS scheduler collects messages sent to the standard error file +by the filter. These messages are relayed to the user based upon the +scheduler LogLevel directive.

+

The type of message is determined by an initial prefix sent on each +line:

+
    +
  • DEBUG: - a debug message
  • +
  • INFO: - an informational message
  • +
  • WARNING: - a warning message
  • +
  • ERROR: - an error message
  • +
  • PAGE: - a page accounting message
  • +
+

If the line of text does not begin with any of the above prefixes, +it is treated as a debug message. Text following the prefix is copied +to the printer-state-message attribute for the printer, +and also added to the error_log unless it is an +informational or page accounting message.

+

Page Accounting

+

Page accounting messages are used to inform the server when one or +more pages are printed. Each line has the form:

+
    +
    +PAGE: page-number copy-count
    +
    +
+

The page-number field is the current page number, starting at +1. The copy-count field specifies the number of copies of that +page that was produced.

+

Page account messages are added to the page_log file and +cause the job-sheets-completed attribute to be updated for +the job.

+

Command-Line Arguments

+

Every filter accepts exactly 6 or 7 command-line arguments:

+
    +
    +printer job user title copies options [filename]
    +
    +
  • printer - The name of the printer queue (normally + this is the name of the program being run)
  • +
  • job - The numeric job ID for the job being printed
  • +
  • user - The string from the originating-user-name + attribute
  • +
  • title - The string from the job-name + attribute
  • +
  • copies - The numeric value from the + number-copies attribute
  • +
  • options - String representations of the job template +attributes, separated by spaces. Boolean attributes are provided as +"name" for true values and "noname" for false values. All other +attributes are provided as "name=value" for single-valued attributes +and "name=value1,value2,...,valueN" for set attributes
  • +
  • filename - The request file
  • +
+

The filename argument is only provided to the first filter in +the chain; all filters must be prepared to read the print file +from the standard input if the filename argument is omitted.

+

Copy Generation

+

The copies argument specifies the number of copies to produce +of the input file. In general, you should only generate copies if the +filename argument is supplied. The only exception to this are +filters that produce device-independent PostScript output (without any +printer commands from the printer's PPD file), since the PostScript +filter pstops is responsible for copy generation.

+

Environment Variables

+

Every filter receives a fixed set of environment variables that can +be used by the filter:

+
    +
  • CHARSET - The character set used by the client for + this print file
  • +
  • CONTENT_TYPE - The original document type, such as + "application/postscript"
  • +
  • CUPS_DATADIR - The location of CUPS data files
  • +
  • CUPS_SERVERROOT - The location of CUPS configuration + files
  • +
  • DEVICE_URI - The output device URI
  • +
  • LANG - The language used by the client for this print +file
  • +
  • PATH - The execution path exported to the filter
  • +
  • PPD - The full filename of the printer's PPD file
  • +
  • PRINTER - The name of the printer queue
  • +
  • RIP_CACHE - The maximum amount of memory each filter + should use
  • +
  • SOFTWARE - The name of the CUPS software, typically + "CUPS/1.1"
  • +
  • TZ - The local timezone
  • +
  • USER - The name of the current user
  • +
+

Dissecting the HP-GL/2 Filter

+

The HP-GL/2 filter (hpgltops) provided with CUPS is a +complex program that converts HP-GL/2 files into device-independent +PostScript output. Since it produces device-independent PostScript +output, it does not need to handle copy generation or writing printer +options from the printer's PPD file.

+

Initializing the Filter

+

The first task of any filter is to ensure that the correct number of +command-line arguments are present:

+
    +
    +if (argc < 6 || argc > 7)
    +{
    +  fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr);
    +  return (1);
    +}
    +
    +
+

After this you open the print file or read from the standard input +as needed:

+
    +
    +FILE *fp;
    +
    +/*
    + * If we have 7 arguments, print the file named on the command-line.
    + * Otherwise, send stdin instead...
    + */
    +
    +if (argc == 6)
    +  fp = stdin;
    +else
    +{
    + /*
    +  * Try to open the print file...
    +  */
    +
    +  if ((fp = fopen(argv[6], "rb")) == NULL)
    +  {
    +    perror("ERROR: unable to open print file - ");
    +    return (1);
    +  }
    +}
    +
    +
+

Once the print file has been opened, options can be processed using +the cupsParseOptions() and cupsGetOption() functions:

+
    +
    +int           num_options;
    +cups_option_t *options;
    +const char    *val;
    +
    +/*
    + * Process command-line options and write the prolog...
    + */
    +
    +options     = NULL;
    +num_options = cupsParseOptions(argv[5], 0, 
    +
    +if ((val = cupsGetOption("blackplot", num_options, options)) != NULL)
    +  shading = 0;
    +
    +if ((val = cupsGetOption("fitplot", num_options, options)) != NULL)
    +  FitPlot = 1;
    +
    +if ((val = cupsGetOption("penwidth", num_options, options)) != NULL)
    +  PenWidth = (float)atoi(val) * 0.001f;
    +
    +
+

After the options have been processed, the filter writes PostScript +code to the standard output based on the print file, closes the print +file (as needed), and returns 0 to the scheduler.

+

PostScript Output

+

Filters that produce PostScript output must generate output +conforming to the Adobe Document Structuring Conventions, 3.0. In +general this means the beginning of each file must begin with:

+
    +
    +%!PS-Adobe-3.0
    +%%BoundingBox: left bottom right top
    +%%Pages: (atend)
    +%%EndComments
    +
    +
+

The left, bottom, right, and top values +are integers in points from the lower-lefthand corner of the page.

+

Pages must be surrounded by:

+
    +
    +%%Page: number number
    +gsave
    +...
    +grestore
    +showpage
    +
    +
+

And the end of each file must contain:

+
    +
    +%%Trailer
    +%%Pages: number-pages
    +%%EOF
    +
    +
+

These comments allow the PostScript filter to correctly perform page +accounting, copy generation, N-up printing, and so forth.

+

4 - Writing Printer Drivers +

+

This chapter discusses how to write a printer driver, which is a +special filter program that converts CUPS raster data into the +appropriate commands and data required for a printer.

+

Overview

+

Raster printers utilitize PPD files that specify one or more +device-specific filters that handle converting print files for the +printer. The simplest raster printer drivers provide a single filter +that converts CUPS raster data to the printer's native format.

+

CUPS Raster Data

+

CUPS raster data (application/vnd.cups-raster) consists +of a stream of raster page descriptions produced by one of the RIP +filters, such as pstoraster or imagetoraster.

+

Each page of data begins with a page dictionary structure called +cups_raster_header_t. This structure contains the +colorspace, bits per color, media size, media type, hardware +resolution, and so forth.

+

After the page dictionary comes the page data which is a +full-resolution, uncompressed bitmap representing the page in the +printer's output colorspace.

+

Page Accounting

+

Printer drivers must handle all page accounting. This means they +must send "PAGE:" messages to the standard error file for each page +(and in many cases, copy) sent to the printer.

+

Color Management

+

Printer drivers can implement their color management via the +cupsColorProfile attributes in the PPD file or internally in the +driver from a device-independent colorspace. In general, color +management performed by the RIP filters is more efficient than that +performed inside printer drivers.

+

For example, the pstoraster filter often only has to +perform a color conversion once each time the color is used for +multiple output pixels, while the raster filter must convert every +pixel on the page.

+

Device and Bitmap Variables

+

Besides the standard PostScript page device dictionary variables +defined in the Adobe PostScript Level 3 reference manual, the CUPS +filters support additional variables that are passed in the page device +dictionary header for the page and in some cases control the type of +raster data that is generated: +

+ + + + + + + + + + + + + + +
VariableTypeDescription
cupsWidthread-only integerWidth of bitmap in +pixels
cupsHeightread-only integer Height of bitmap +in pixels
cupsMediaTyperead-write integer +Device-specific media type code
cupsBitsPerColorread-write integerNumber of +bits per color; 1, 2, 4, and 8 are currently supported
cupsBitsPerPixelread-only integer Number of +bits per pixel; 1 to 32
cupsBytesPerLineread-only integerNumber of +bytes per line of raster graphics
cupsColorOrderread-write enumThe order of +color values in the bitmap: +
    +
  • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK
  • +
  • CUPS_ORDER_BANDED - CCC MMM YYY KKK
  • +
  • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ...
  • +
+
cupsColorSpaceread-write enumThe colorspace +of the bitmap: +
    +
  • CUPS_CSPACE_W - White (luminance)
  • +
  • CUPS_CSPACE_RGB - Red, green, blue
  • +
  • CUPS_CSPACE_RGBA - Red, green, blue, alpha
  • +
  • CUPS_CSPACE_K - Black
  • +
  • CUPS_CSPACE_CMY - Cyan, magenta, yellow
  • +
  • CUPS_CSPACE_YMC - Yellow, magenta, cyan
  • +
  • CUPS_CSPACE_CMYK - Cyan, magenta, yellow, black
  • +
  • CUPS_CSPACE_YMCK - Yellow, magenta, cyan, black
  • +
  • CUPS_CSPACE_KCMY - Black, cyan, magenta, yellow
  • +
  • CUPS_CSPACE_KCMYcm - Black, cyan, magenta, yellow, + light cyan, light magenta
  • +
  • CUPS_CSPACE_GMCK - Metallic yellow (gold), metallic +magenta, metallic cyan, black
  • +
  • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic +magenta, metallic cyan, metallic grey (silver)
  • +
  • CUPS_CSPACE_WHITE - White pigment (black as white +pigment)
  • +
  • CUPS_CSPACE_GOLD - Gold foil (black as gold foil)
  • +
  • CUPS_CSPACE_SILVER - Silver foil (black as silver +foil)
  • +
+
cupsCompressionread-write integer +Device-specific compression type code
cupsRowCountread-write integerDevice-specific +row count value
cupsRowFeedread-write integerDevice-specific +row feed value
cupsRowStepread-write integerDevice-specific +row step value
+
+

+

Bitmaps with a colorspace of CUPS_CSPACE_KCMYcm and more than 1 bit +per color are transmitted to the raster driver in KCMY colorspace; the +driver is responsible for producing the correct separation of normal +and light cyan and magenta inks.

+

Dissecting the HP-PCL Driver

+

The HP-PCL driver provided with CUPS (rastertohp) +converts bitmap data from the raster filters into HP-PCL commands for +most PCL-compatible printers. The actual format of the raster data is +controlled by the PPD file being used - deskjet.ppd or +laserjet.ppd.

+

PPD Files

+

PPD files play an important part of all raster printer drivers. +Options defined in the PPD file contain PostScript commands that +control the raster data that is sent to the printer driver.

+

A typical CUPS printer driver will include ColorModel, +InputSlot, PageSize, PageRegion, and +Resolution options. Each option is shown using the standard PPD +format:

+
    +
    +*OpenUI *PageSize/Media Size: PickOne
    +*OrderDependency: 10 AnySetup *PageSize
    +*DefaultPageSize: Letter
    +*PageSize Letter/US Letter: "<<
    +/PageSize [612 792]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*PageSize Legal/US Legal: "<<
    +/PageSize [612 1008]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*PageSize A4/A4: "<<
    +/PageSize [595 842]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*CloseUI: *PageSize
    +
    +
+

The OpenUI keyword specifies the new option. The first +name is the option with an asterisk (*) in front of it. The first name +is usually followed by a slash (/) and a human-readable version of the +option name.

+

Every option must have a default value, specified using the +DefaultOption keyword.

+

Each option begins with the option name followed by the computer and +human-readable values. The PostScript commands follow these inside +double quotes. PostScript commands can be provided on a single line:

+
    +
    +*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>> setpagedevice"
    +
    +
+

or broken down on separate lines using the End keyword +to terminate them:

+
    +
    +*PageSize A4/A4: "<<
    +/PageSize [595 842]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +
    +
+

The choice of the two formats is usually esthetic. However, each +line in a PPD file must not exceed 255 characters, so if your +PostScript commands are long you may need to break them up on separate +lines.

+

Reading Raster Data

+

As with any filter, your printer driver should handle raster data +from a filename specified on the command-line or from the standard +input. The cupsRasterOpen() + function opens a raster stream for printing:

+
    +
    +int           fd;   /* File descriptor */
    +cups_raster_t *ras; /* Raster stream for printing */
    +
    +
    +/*
    + * Check for valid arguments...
    + */
    +
    +if (argc < 6 || argc > 7)
    +{
    + /*
    +  * We don't have the correct number of arguments; write an error message
    +  * and return.
    +  */
    +
    +  fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr);
    +  return (1);
    +}
    +
    +/*
    + * Open the page stream...
    + */
    +
    +if (argc == 7)
    +{
    +  if ((fd = open(argv[6], O_RDONLY)) == -1)
    +  {
    +    perror("ERROR: Unable to open raster file - ");
    +    sleep(1);
    +    return (1);
    +  }
    +}
    +else
    +  fd = 0;
    +
    +ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
    +
    +
+

Once you have opened the raster stream you just need to read each +page and print it:

+
    +
    +cups_raster_header_t header;
    +int                  y;
    +unsigned char        data[8192];
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ... initialize the printer ...
    +  for (y = header.cupsHeight; y > 0; y ++)
    +  {
    +    cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
    +    ... send raster line to printer ...
    +  }
    +}
    +
    +
+

After you have processed all pages, close the raster stream and +return:

+
    +
    +cupsRasterClose(ras);
    +
    +return (0);
    +
    +
+

5 - Writing Backends

+

This chapter describes how to write a backend for CUPS. Backends +communicate directly with printers and allow printer drivers and +filters to send data using any type of connection transparently.

+

Overview

+

Backends are special filters that communicate with printers +directly. They are treated slightly differently than filters, however, +and have some unique requirements.

+

Security Considerations

+

Backends are run as the root user, so special care must be taken to +avoid potential security violations. In particular, remember that a +backend will be able to manipulate disk files, devices, and other +resources that potentially could damage a system or printer.

+

Command-Line Arguments

+

Besides the standard filter arguments, backends are also run with no +arguments to get a list of available devices. This discovery process is +described later in this chapter.

+

Copy Generation

+

Like filters, backends should send multiple copies of the print file +only if a filename is supplied on the command-line. Otherwise the +backend should assume that the upstream filter has already added the +necessary commands or data to produce the multiple copies.

+

Page Accounting

+

Backend filters generally do not do page accounting, however they +should at a minimum produce a single page message for each copy that is +produced when a filename is present on the command-line. This is +because the user selected "raw" printing and no other accounting +information is possible.

+

Exclusive Access

+

Backends that talk to local character or block devices should open +the device file in exclusive mode (O_EXCL) to cooperate +with other printers defined for the same device.

+

Retries

+

All backends must retry connections to the device. This +includes backends that talk to local character or block devices, as the +user may define more than one printer queue pointing at the same +physical device.

+

To prevent excess CPU utilitization, the backend should go to sleep +for an amount of time between retries; the CUPS-supplied backends retry +once every 30 seconds.

+

Dissecting the Serial Port Backend

+

The serial port backend provides support for serial printers. Since +it does everything a good backend needs to do, it provides an excellent +example of what to do.

+

Supporting Device Discovery

+

As previously noted, backends are special filter programs that talk +to printer devices. Another task a backend must perform is to list the +available devices it supports. The backend lists the available devices +when no additioanl arguments are supplied on the command-line (i.e. +just the command name...)

+

The serial backend lists devices by looking at serial port files in +the /dev directory, by consulting a hardware inventory +(IRIX), and in some cases by trying to open the ports to see if they +actually exist.

+

Once it finds a serial port it writes a single line for each port to +the standard error file. Each line looks like this:

+
    +
    +serial serial:/dev/ttyS0?baud=115200 "Unknown" "Serial Port 1"
    +
    +
+

The first word "serial" is the device class; this identifies +the class of device which can be used to categorize it in user +interfaces. CUPS currently recognizes the following classes:

+
    +
  • "file" - a disk file.
  • +
  • "direct" - a parallel or fixed-rate serial data port, currently +used for Centronics, IEEE-1284, and USB printer ports.
  • +
  • "serial" - a variable-rate serial port.
  • +
  • "network" - a network connection, typically via AppSocket, HTTP, +IPP, LPD, or SMB/CIFS protocols.
  • +
+

After the device class is the device URI, in this case +"serial:/dev/ttyS0?baud=115200". This is the URI that should be used by +the user to select this port. For serial ports, the "baud=115200" +specifies the maximum baud rate supported by the port - the actual +value will vary based on the speed the user selects for the printer.

+

The last two strings are the model and description for the port. The +"Unknown" string means that the printer model is unknown - some devices +are able to provide a make and model such as "HP DeskJet" that allows +users and software to choose an appropriate printer driver more easily. +Both the model and description must be enclosed inside double quotes.

+

Opening the Serial Port

+

As noted previously, all backends should open device files in +exclusive mode, and retry as needed until the port is available. The +serial port does this using a do-while loop:

+
    +
    +do
    +{
    +  if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
    +  {
    +    if (errno == EBUSY)
    +    {
    +      fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
    +      sleep(30);
    +    }
    +    else
    +    {
    +      perror("ERROR: Unable to open serial port device file");
    +      return (1);
    +    }
    +  }
    +}
    +while (fd < 0);
    +
    +
+

If the port is busy or in use by another process, the backend will +go to sleep for 30 seconds and try again. If another error is detected +a message is sent to the user and the backend aborts the print job +until the problem can be corrected.

+

Writing Data to the Port

+

Network and character devices pose an interesting problem when +writing data to the port - they may not be able to write all of the +bytes in your buffer before returning. To work around this problem you +must loop until all bytes have been written:

+
    +
    +while (nbytes > 0)
    +{
    +  if ((wbytes = write(fd, bufptr, nbytes)) < 0)
    +    if (errno == ENOTTY)
    +      wbytes = write(fd, bufptr, nbytes);
    +
    +  if (wbytes < 0)
    +  {
    +    perror("ERROR: Unable to send print file to printer");
    +    break;
    +  }
    +
    +  nbytes -= wbytes;
    +  bufptr += wbytes;
    +}
    +
    +
+

The check for the ENOTTY error is needed on some +platforms to clear an error from a previous ioctl() call.

+

Finishing Up

+

Once you have sent the print file, return 0 if the file printed +successfully or 1 if it did not. This will allow the scheduler to stop +the print job if there is a device error, preserving the print job for +later printing once the problem has been corrected.

+

A - Software License Agreement

+

Common UNIX Printing System License +Agreement

+

Copyright 1997-2001 by Easy Software Products +
44141 AIRPORT VIEW DR STE 204 +
HOLLYWOOD, MARYLAND 20636-3111 USA +
+
Voice: +1.301.373.9600 +
Email: cups-info@cups.org +
WWW: http://www.cups.org

+

Introduction

+

The Common UNIX Printing SystemTM, ("CUPSTM"), +is provided under the GNU General Public License ("GPL") and GNU +Library General Public License ("LGPL"), Version 2. A copy of these +licenses follow this introduction.

+

The GNU LGPL applies to the CUPS API library, located in the "cups" +subdirectory of the CUPS source distribution and in the +"/usr/include/cups" directory and "libcups.a", "libcups.sl", or +"libcups.so" files in the binary distributions.

+

The GNU GPL applies to the remainder of the CUPS distribution, +including the "pstoraster" filter which is based upon GNU Ghostscript +5.50 and the "pdftops" filter which is based upon Xpdf 0.90.

+

For those not familiar with the GNU GPL, the license basically +allows you to:

+
    +
  • Use the CUPS software at no charge.
  • +
  • Distribute verbatim copies of the software in source or binary +form.
  • +
  • Sell verbatim copies of the software for a media fee, or sell +support for the software.
  • +
  • Distribute or sell printer drivers and filters that use CUPS so +long as source code is made available under the GPL.
  • +
+

What this license does not allow you to do is make changes or +add features to CUPS and then sell a binary distribution without source +code. You must provide source for any new drivers, changes, or +additions to the software, and all code must be provided under the GPL +or LGPL as appropriate.

+

The GNU LGPL relaxes the "link-to" restriction, allowing you to +develop applications that use the CUPS API library under other licenses +and/or conditions as appropriate for your application.

+

Trademarks

+

Easy Software Products has trademarked the Common UNIX Printing +System, CUPS, and CUPS logo. These names and logos may be used freely +in any direct port or binary distribution of CUPS. To use them in +derivative products, please contract Easy Software Products for written +permission. Our intention is to protect the value of these trademarks +and ensure that any derivative product meets the same high-quality +standards as the original.

+

Binary Distribution Rights

+

Easy Software Products also sells rights to the CUPS source code +under a binary distribution license for vendors that are unable to +release source code for their drivers, additions, and modifications to +CUPS under the GNU GPL and LGPL. For information please contact us at +the address shown above.

+

The Common UNIX Printing System provides a "pstoraster" filter that +utilizes the GNU GhostScript 5.50 core to convert PostScript files into +a stream of raster images. For binary distribution licensing of this +software, please contact:

Miles Jones +
Director of Marketing +
Artifex Software Inc. +
454 Las Gallinas Ave., Suite 108 +
San Rafael, CA 94903 USA +
Voice: +1.415.492.9861 +
Fax: +1.415.492.9862 +
EMail: info@arsoft.com
+

+

The "pdftops" filter is based on the Xpdf 0.90 software. For binary +distribution licensing of this software, please contact:

+ Derek B. Noonburg +
Email: derekn@foolabs.com +
WWW: +http://www.foolabs.com/xpdf/

+

Support

+

Easy Software Products sells software support for CUPS as well as a +commercial printing product based on CUPS called ESP Print Pro. You can +find out more at our web site:

+ + + + +

GNU GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not allowed.
+
+
+
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it.

+

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights.

+

We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the software.

+

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, +so that any problems introduced by others will not reflect on the +original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all.

+

The precise terms and conditions for copying, distribution and +modification follow.

+

GNU GENERAL PUBLIC LICENSE +
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND +MODIFICATION

+
    +
  1. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you".
  2. +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does.

    +
  3. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the +Program.
  4. +

    You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

    +
  5. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: +
      +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change.
    2. +
    3. You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License.
    4. +
    5. if the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the most ordinary way, to print or display an announcement including +an appropriate copyright notice and a notice that there is no warranty +(or else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling the user +how to view a copy of this License. (Exception: if the Program itself +is interactive but does not normally print such an announcement, your +work based on the Program is not required to print an announcement.)
    6. +
    +
  6. +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

    +

    Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Program.

    +

    In addition, mere aggregation of another work not based on the +Program with the Program (or with a work based on the Program) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

    +
  7. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +
      +
    1. Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or,
    2. +
    3. Accompany it with a written offer, valid for at least three years, +to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or,
    4. +
    5. Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in accord +with Subsection b above.)
    6. +
    +
  8. +

    The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that +is normally distributed (in either source or binary form) with the +major components (compiler, kernel, and so on) of the operating system +on which the executable runs, unless that component itself accompanies +the executable.

    +

    If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent access +to copy the source code from the same place counts as distribution of +the source code, even though third parties are not compelled to copy +the source along with the object code.

    +
  9. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such parties +remain in full compliance.
  10. +
  11. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying the +Program or works based on it.
  12. +
  13. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License.
  14. +
  15. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program.
  16. +

    If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply and the section as a whole is intended to apply in +other circumstances.

    +

    It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.

    +

    This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

    +
  17. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License.
  18. +
  19. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns.
  20. +

    Each version is given a distinguishing version number. If the +Program specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation.

    +
  21. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally.
  22. +
+

NO WARRANTY

+
    +
  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS +WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  2. +
  3. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.
  4. +
+

END OF TERMS AND CONDITIONS

+ + + +

GNU LIBRARY GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright (C) 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users.

+

This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it.

+

For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights.

+

Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library.

+

Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all.

+

Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License, which was designed for utility +programs. This license, the GNU Library General Public License, +applies to certain designated libraries. This license is quite +different from the ordinary one; be sure to read it in full, and don't +assume that anything in it is the same as in the ordinary license.

+

The reason we have a separate public license for some libraries is +that they blur the distinction we usually make between modifying or +adding to a program and simply using it. Linking a program with a +library, without changing the library, is in some sense simply using +the library, and is analogous to running a utility program or +application program. However, in a textual and legal sense, the linked +executable is a combined work, a derivative of the original library, +and the ordinary General Public License treats it as such.

+

Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better.

+

However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended +to permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to +achieve this as regards changes in header files, but we have achieved +it as regards changes in the actual functions of the Library.) The +hope is that this will lead to faster development of free libraries.

+

The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library.

+

Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one.

+

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

0. This License Agreement applies to any software +library which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Library General Public License (also called "this License"). Each +licensee is addressed as "you".

+

A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables.

+

The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".)

+

"Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library.

+

Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does and +what the program that uses the Library does.

+

1. You may copy and distribute verbatim copies of +the Library's complete source code as you receive it, in any medium, +provided that you conspicuously and appropriately publish on each copy +an appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the Library.

+

You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

+

2. You may modify your copy or copies of the +Library or any portion of it, thus forming a work based on the Library, +and copy and distribute such modifications or work under the terms of +Section 1 above, provided that you also meet all of these conditions:

+
    +
  1. The modified work must itself be a software library.
  2. +

    +
  3. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change.
  4. +

    +
  5. You must cause the whole of the work to be licensed at no charge +to all third parties under the terms of this License.
  6. +

    +
  7. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses the +facility, other than as an argument passed when the facility is +invoked, then you must make a good faith effort to ensure that, in the +event an application does not supply such function or table, the +facility still operates, and performs whatever part of its purpose +remains meaningful.
  8. +

    (For example, a function in a library to compute square roots has a +purpose that is entirely well-defined independent of the application. + Therefore, Subsection 2d requires that any application-supplied +function or table used by this function must be optional: if the +application does not supply it, the square root function must still +compute square roots.)

    +
+

These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

+

Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Library.

+

In addition, mere aggregation of another work not based on the +Library with the Library (or with a work based on the Library) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

+

3. You may opt to apply the terms of the ordinary +GNU General Public License instead of this License to a given copy of +the Library. To do this, you must alter all the notices that refer to +this License, so that they refer to the ordinary GNU General Public +License, version 2, instead of to this License. (If a newer version +than version 2 of the ordinary GNU General Public License has appeared, +then you can specify that version instead if you wish.) Do not make +any other change in these notices.

+

Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy.

+

This option is useful when you wish to copy part of the code of the +Library into a program that is not a library.

+

4. You may copy and distribute the Library (or a +portion or derivative of it, under Section 2) in object code or +executable form under the terms of Sections 1 and 2 above provided that +you accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange.

+

If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to distribute +the source code, even though third parties are not compelled to copy +the source along with the object code.

+

5. A program that contains no derivative of any +portion of the Library, but is designed to work with the Library by +being compiled or linked with it, is called a "work that uses the +Library". Such a work, in isolation, is not a derivative work of the +Library, and therefore falls outside the scope of this License.

+

However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. Section +6 states terms for distribution of such executables.

+

When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law.

+

If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.)

+

Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, whether +or not they are linked directly with the Library itself.

+

6. As an exception to the Sections above, you may +also compile or link a "work that uses the Library" with the Library to +produce a work containing portions of the Library, and distribute that +work under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications.

+

You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things:

+
    +
  1. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that uses +the Library", as object code and/or source code, so that the user can +modify the Library and then relink to produce a modified executable +containing the modified Library. (It is understood that the user who +changes the contents of definitions files in the Library will not +necessarily be able to recompile the application to use the modified +definitions.)
  2. +

    +
  3. Accompany the work with a written offer, valid for at least three +years, to give the same user the materials specified in Subsection 6a, +above, for a charge no more than the cost of performing this +distribution.
  4. +

    +
  5. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place.
  6. +

    +
  7. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy.
  8. +
+

For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major components +(compiler, kernel, and so on) of the operating system on which the +executable runs, unless that component itself accompanies the +executable.

+

It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute.

+

7. You may place library facilities that are a work +based on the Library side-by-side in a single library together with +other library facilities not covered by this License, and distribute +such a combined library, provided that the separate distribution of the +work based on the Library and of the other library facilities is +otherwise permitted, and provided that you do these two things:

+
    +
  1. Accompany the combined library with a copy of the same work based +on the Library, uncombined with any other library facilities. This +must be distributed under the terms of the Sections above.
  2. +

    +
  3. Give prominent notice with the combined library of the fact that +part of it is a work based on the Library, and explaining where to +find the accompanying uncombined form of the same work.
  4. +
+

8. You may not copy, modify, sublicense, link with, +or distribute the Library except as expressly provided under this +License. Any attempt otherwise to copy, modify, sublicense, link with, +or distribute the Library is void, and will automatically terminate +your rights under this License. However, parties who have received +copies, or rights, from you under this License will not have their +licenses terminated so long as such parties remain in full compliance.

+

9. You are not required to accept this License, +since you have not signed it. However, nothing else grants you +permission to modify or distribute the Library or its derivative works. + These actions are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Library (or any work based +on the Library), you indicate your acceptance of this License to do so, +and all its terms and conditions for copying, distributing or modifying +the Library or works based on it.

+

10. Each time you redistribute the Library (or any +work based on the Library), the recipient automatically receives a +license from the original licensor to copy, distribute, link with or +modify the Library subject to these terms and conditions. You may not +impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance +by third parties to this License.

+

11. If, as a consequence of a court judgment or +allegation of patent infringement or for any other reason (not limited +to patent issues), conditions are imposed on you (whether by court +order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. + If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Library at all. For +example, if a patent license would not permit royalty-free +redistribution of the Library by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Library.

+

If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply, and the section as a whole is intended to apply in +other circumstances.

+

It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up +to the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice.

+

This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

+

12. If the distribution and/or use of the Library +is restricted in certain countries either by patents or by copyrighted +interfaces, the original copyright holder who places the Library under +this License may add an explicit geographical distribution limitation +excluding those countries, so that distribution is permitted only in or +among countries not thus excluded. In such case, this License +incorporates the limitation as if written in the body of this License.

+

13. The Free Software Foundation may publish +revised and/or new versions of the Library General Public License from +time to time. Such new versions will be similar in spirit to the +present version, but may differ in detail to address new problems or +concerns.

+

Each version is given a distinguishing version number. If the +Library specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation.

+

14. If you wish to incorporate parts of the Library +into other free programs whose distribution conditions are incompatible +with these, write to the author to ask for permission. For software +which is copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally.

+

NO WARRANTY

+

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, +THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW +OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY +WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL +OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.

+

END OF TERMS AND CONDITIONS

+

B - Constants

+

This appendix lists all of the constants that are defined by the +CUPS API.

+

CUPS Constants

+

Version Number

+

The CUPS_VERSION constant is a floating-point number +representing the API version number. The current version number is +1.0100 which represents CUPS version 1.1.0.

+

Printer Capabilities

+

The CUPS_PRINTER constants represent capability bits +for printers and classes:

+
    +
  • CUPS_PRINTER_LOCAL - Is a local printer or class.
  • +
  • CUPS_PRINTER_REMOTE - Is a remote printer or class.
  • +
  • CUPS_PRINTER_CLASS - Is a class.
  • +
  • CUPS_PRINTER_BW - Printer prints in black and white.
  • +
  • CUPS_PRINTER_COLOR - Printer prints in color.
  • +
  • CUPS_PRINTER_DUPLEX - Printer can print double-sided.
  • +
  • CUPS_PRINTER_STAPLE - Printer can staple output.
  • +
  • CUPS_PRINTER_COPIES - Printer can produce multiple + copies on its own.
  • +
  • CUPS_PRINTER_COLLATE - Printer can collate copies.
  • +
  • CUPS_PRINTER_PUNCH - Printer can punch holes in +output.
  • +
  • CUPS_PRINTER_COVER - Printer can put covers on output.
  • +
  • CUPS_PRINTER_BIND - Printer can bind output.
  • +
  • CUPS_PRINTER_SORT - Printer can sort output.
  • +
  • CUPS_PRINTER_SMALL - Printer can print on media up to +9x14 inches.
  • +
  • CUPS_PRINTER_MEDIUM - Printer can print on media from +9x14 to 18x24 inches.
  • +
  • CUPS_PRINTER_LARGE - Printer can print on media + larger than 18x24 inches.
  • +
  • CUPS_PRINTER_VARIABLE - Printer can print on variable +or custom media sizes.
  • +
  • CUPS_PRINTER_IMPLICIT - Is an implicit class.
  • +
  • CUPS_PRINTER_OPTIONS - All of the printer capability + and option bits.
  • +
+

Encodings

+

CUPS defines the following character set encoding constants:

+
    +
  • CUPS_US_ASCII - US ASCII character set.
  • +
  • CUPS_UTF_8 - UTF-8 encoding of Unicode.
  • +
  • CUPS_ISO8859_1 - ISO-8859-1 character set.
  • +
  • CUPS_ISO8859_2 - ISO-8859-2 character set.
  • +
  • CUPS_ISO8859_3 - ISO-8859-3 character set.
  • +
  • CUPS_ISO8859_4 - ISO-8859-4 character set.
  • +
  • CUPS_ISO8859_5 - ISO-8859-5 character set.
  • +
  • CUPS_ISO8859_6 - ISO-8859-6 character set.
  • +
  • CUPS_ISO8859_7 - ISO-8859-7 character set.
  • +
  • CUPS_ISO8859_8 - ISO-8859-8 character set.
  • +
  • CUPS_ISO8859_9 - ISO-8859-9 character set.
  • +
  • CUPS_ISO8859_10 - ISO-8859-10 character set.
  • +
  • CUPS_ISO8859_13 - ISO-8859-13 character set.
  • +
  • CUPS_ISO8859_14 - ISO-8859-14 character set.
  • +
  • CUPS_ISO8859_15 - ISO-8859-15 character set.
  • +
  • CUPS_WINDOWS_874 - Windows code page 874.
  • +
  • CUPS_WINDOWS_1250 - Windows code page 1250.
  • +
  • CUPS_WINDOWS_1251 - Windows code page 1251.
  • +
  • CUPS_WINDOWS_1252 - Windows code page 1252.
  • +
  • CUPS_WINDOWS_1253 - Windows code page 1253.
  • +
  • CUPS_WINDOWS_1254 - Windows code page 1254.
  • +
  • CUPS_WINDOWS_1255 - Windows code page 1255.
  • +
  • CUPS_WINDOWS_1256 - Windows code page 1256.
  • +
  • CUPS_WINDOWS_1257 - Windows code page 1257.
  • +
  • CUPS_WINDOWS_1258 - Windows code page 1258.
  • +
+

HTTP Constants

+

Limits

+

The following constants define the limits for strings:

+
    +
  • HTTP_MAX_BUFFER - Size of socket buffer.
  • +
  • HTTP_MAX_HOST - Maximum length of hostname.
  • +
  • HTTP_MAX_URI - Maximum length of URI.
  • +
  • HTTP_MAX_VALUE - Maximum length of field values.
  • +
+

Status Codes

+

The following status codes can be returned by httpUpdate() +:

+
    +
  • HTTP_ERROR - A network error occurred
  • +
  • HTTP_CONTINUE - Continue response from HTTP proxy
  • +
  • HTTP_OK - OPTIONS/GET/HEAD/POST/TRACE command was +successful
  • +
  • HTTP_CREATED - PUT command was successful
  • +
  • HTTP_ACCEPTED - DELETE command was successful
  • +
  • HTTP_NOT_AUTHORITATIVE - Information isn't +authoritative
  • +
  • HTTP_NO_CONTENT - Successful command
  • +
  • HTTP_RESET_CONTENT - Content was reset/recreated
  • +
  • HTTP_PARTIAL_CONTENT - Only a partial file was +recieved/sent
  • +
  • HTTP_MULTIPLE_CHOICES - Multiple files match request
  • +
  • HTTP_MOVED_PERMANENTLY - Document has moved +permanently
  • +
  • HTTP_MOVED_TEMPORARILY - Document has moved +temporarily
  • +
  • HTTP_SEE_OTHER - See this other link...
  • +
  • HTTP_NOT_MODIFIED - File not modified
  • +
  • HTTP_USE_PROXY - Must use a proxy to access this URI
  • +
  • HTTP_BAD_REQUEST - Bad request
  • +
  • HTTP_UNAUTHORIZED - Unauthorized to access host
  • +
  • HTTP_PAYMENT_REQUIRED - Payment required
  • +
  • HTTP_FORBIDDEN - Forbidden to access this URI
  • +
  • HTTP_NOT_FOUND - URI was not found
  • +
  • HTTP_METHOD_NOT_ALLOWED - Method is not allowed
  • +
  • HTTP_NOT_ACCEPTABLE - Not Acceptable
  • +
  • HTTP_PROXY_AUTHENTICATION - Proxy Authentication is +Required
  • +
  • HTTP_REQUEST_TIMEOUT - Request timed out
  • +
  • HTTP_CONFLICT - Request is self-conflicting
  • +
  • HTTP_GONE - Server has gone away
  • +
  • HTTP_LENGTH_REQUIRED - A content length or encoding is +required
  • +
  • HTTP_PRECONDITION - Precondition failed
  • +
  • HTTP_REQUEST_TOO_LARGE - Request entity too large
  • +
  • HTTP_URI_TOO_LONG - URI too long
  • +
  • HTTP_UNSUPPORTED_MEDIATYPE - The requested media type +is unsupported
  • +
  • HTTP_SERVER_ERROR - Internal server error
  • +
  • HTTP_NOT_IMPLEMENTED - Feature not implemented
  • +
  • HTTP_BAD_GATEWAY - Bad gateway
  • +
  • HTTP_SERVICE_UNAVAILABLE - Service is unavailable
  • +
  • HTTP_GATEWAY_TIMEOUT - Gateway connection timed out
  • +
  • HTTP_NOT_SUPPORTED - HTTP version not supported
  • +
+

Fields

+

The following fields are indices for each of the standard HTTP +fields in HTTP 1/1:

+
    +
  • HTTP_FIELD_ACCEPT_LANGUAGE - Accept-Language
  • +
  • HTTP_FIELD_ACCEPT_RANGES - Accept-Ranges
  • +
  • HTTP_FIELD_AUTHORIZATION - Authorization
  • +
  • HTTP_FIELD_CONNECTION - Connection
  • +
  • HTTP_FIELD_CONTENT_ENCODING - Content-Encoding
  • +
  • HTTP_FIELD_CONTENT_LANGUAGE - Content-Language
  • +
  • HTTP_FIELD_CONTENT_LENGTH - Content-Length
  • +
  • HTTP_FIELD_CONTENT_LOCATION - Content-Location
  • +
  • HTTP_FIELD_CONTENT_MD5 - Content-MD5
  • +
  • HTTP_FIELD_CONTENT_RANGE - Content-Range
  • +
  • HTTP_FIELD_CONTENT_TYPE - Content-Type
  • +
  • HTTP_FIELD_CONTENT_VERSION - Content-Version
  • +
  • HTTP_FIELD_DATE - Date
  • +
  • HTTP_FIELD_HOST - Host
  • +
  • HTTP_FIELD_IF_MODIFIED_SINCE - If-Modified-Since
  • +
  • HTTP_FIELD_IF_UNMODIFIED_SINCE - If-Unmodified-Since
  • +
  • HTTP_FIELD_KEEP_ALIVE - Keep-Alive
  • +
  • HTTP_FIELD_LAST_MODIFIED - Last-Modified
  • +
  • HTTP_FIELD_LINK - Link
  • +
  • HTTP_FIELD_LOCATION - Location
  • +
  • HTTP_FIELD_RANGE - Range
  • +
  • HTTP_FIELD_REFERER - Referer
  • +
  • HTTP_FIELD_RETRY_AFTER - Retry-After
  • +
  • HTTP_FIELD_TRANSFER_ENCODING - Transfer-Encoding
  • +
  • HTTP_FIELD_UPGRADE - Upgrade
  • +
  • HTTP_FIELD_USER_AGENT - User-Agent
  • +
  • HTTP_FIELD_WWW_AUTHENTICATE - WWW-Authenticate
  • +
+

IPP Constants

+

Limits

+

The following constants define array limits for IPP data:

+
    +
  • IPP_MAX_NAME - Maximum length of an attribute name
  • +
  • IPP_MAX_VALUES - Maximum number of set-of values that +can be read in a request.
  • +
+

Tags

+
    +
  • IPP_TAG_ZERO - Wildcard tag value for searches; also + used to separate groups of attributes
  • +
  • IPP_TAG_OPERATION - Tag for values of type operation
  • +
  • IPP_TAG_JOB - Tag for values of type job
  • +
  • IPP_TAG_END - Tag for values of type end
  • +
  • IPP_TAG_PRINTER - Tag for values of type printer
  • +
  • IPP_TAG_UNSUPPORTED_GROUP - Tag for values of type +unsupported_group
  • +
  • IPP_TAG_UNSUPPORTED_VALUE - Tag for values of type +unsupported_value
  • +
  • IPP_TAG_DEFAULT - Tag for values of type default
  • +
  • IPP_TAG_UNKNOWN - Tag for values of type unknown
  • +
  • IPP_TAG_NOVALUE - Tag for values of type novalue
  • +
  • IPP_TAG_NOTSETTABLE - Tag for values of type +notsettable
  • +
  • IPP_TAG_DELETEATTR - Tag for values of type deleteattr
  • +
  • IPP_TAG_ANYVALUE - Tag for values of type anyvalue
  • +
  • IPP_TAG_INTEGER - Tag for values of type integer
  • +
  • IPP_TAG_BOOLEAN - Tag for values of type boolean
  • +
  • IPP_TAG_ENUM - Tag for values of type enum
  • +
  • IPP_TAG_STRING - Tag for values of type string
  • +
  • IPP_TAG_DATE - Tag for values of type date
  • +
  • IPP_TAG_RESOLUTION - Tag for values of type resolution
  • +
  • IPP_TAG_RANGE - Tag for values of type range
  • +
  • IPP_TAG_COLLECTION - Tag for values of type collection
  • +
  • IPP_TAG_TEXTLANG - Tag for values of type textlang
  • +
  • IPP_TAG_NAMELANG - Tag for values of type namelang
  • +
  • IPP_TAG_TEXT - Tag for values of type text
  • +
  • IPP_TAG_NAME - Tag for values of type name
  • +
  • IPP_TAG_KEYWORD - Tag for values of type keyword
  • +
  • IPP_TAG_URI - Tag for values of type uri
  • +
  • IPP_TAG_URISCHEME - Tag for values of type urischeme
  • +
  • IPP_TAG_CHARSET - Tag for values of type charset
  • +
  • IPP_TAG_LANGUAGE - Tag for values of type language
  • +
  • IPP_TAG_MIMETYPE - Tag for values of type mimetype
  • +
+

Resolution Units

+

The IPP_RES_PER_INCH and IPP_RES_PER_CM + constants specify dots per inch and dots per centimeter, respectively.

+

Finishings

+

The finishing values specify special finishing operations to be +performed on the job.

+
    +
  • IPP_FINISH_NONE - Do no finishing
  • +
  • IPP_FINISH_STAPLE - Staple the job
  • +
  • IPP_FINISH_PUNCH - Punch the job
  • +
  • IPP_FINISH_COVER - Cover the job
  • +
  • IPP_FINISH_BIND - Bind the job
  • +
+

Orientations

+

The orientation values specify the orientation of the job.

+
    +
  • IPP_PORTRAIT - No rotation
  • +
  • IPP_LANDSCAPE - 90 degrees counter-clockwise
  • +
  • IPP_REVERSE_LANDSCAPE - 90 degrees clockwise
  • +
  • IPP_REVERSE_PORTRAIT - 180 degrees
  • +
+

Qualities

+

The quality values specify the desired quality of the print.

+
    +
  • IPP_QUALITY_DRAFT - Draft quality
  • +
  • IPP_QUALITY_NORMAL - Normal quality
  • +
  • IPP_QUALITY_HIGH - High quality
  • +
+

Job States

+

The job state values are used to represent the current job state.

+
    +
  • IPP_JOB_PENDING - Job is pending
  • +
  • IPP_JOB_HELD - Job is held
  • +
  • IPP_JOB_PROCESSING - Job is processing
  • +
  • IPP_JOB_STOPPED - Job is stopped
  • +
  • IPP_JOB_CANCELLED - Job is cancelled
  • +
  • IPP_JOB_ABORTED - Job is aborted
  • +
  • IPP_JOB_COMPLETED - Job is completed
  • +
+

Printer States

+

The printer state values are used to represent the current printer +state.

+
    +
  • IPP_PRINTER_IDLE - Printer is idle
  • +
  • IPP_PRINTER_PROCESSING - Printer is processing
  • +
  • IPP_PRINTER_STOPPED - Printer is stopped
  • +
+

Operations

+

The operation values represent the available IPP operations.

+
    +
  • IPP_PRINT_JOB - Print a file
  • +
  • IPP_PRINT_URI - Print a URI
  • +
  • IPP_VALIDATE_JOB - Validate job attributes
  • +
  • IPP_CREATE_JOB - Create a new job
  • +
  • IPP_SEND_DOCUMENT - Send a document to a job
  • +
  • IPP_SEND_URI - Send a URI to a job
  • +
  • IPP_CANCEL_JOB - Cancel a job
  • +
  • IPP_GET_JOB_ATTRIBUTES - Get job attributes
  • +
  • IPP_GET_JOBS - Get a list of all jobs
  • +
  • IPP_GET_PRINTER_ATTRIBUTES - Get printer attributes
  • +
  • IPP_HOLD_JOB - Hold a pending job
  • +
  • IPP_RELEASE_JOB - Release a held job
  • +
  • IPP_RESTART_JOB - Restart a completed job
  • +
  • IPP_PAUSE_PRINTER - Pause a printer
  • +
  • IPP_RESUME_PRINTER - Restart a paused printer
  • +
  • IPP_PURGE_JOBS - Purge jobs from the queue
  • +
  • IPP_SET_PRINTER_ATTRIBUTES - Set printer attributes
  • +
  • IPP_SET_JOB_ATTRIBUTES - Set job attributes
  • +
  • IPP_GET_PRINTER_SUPPORTED_VALUES - Get printer +supported values
  • +
  • CUPS_GET_DEFAULT - Get the default destination
  • +
  • CUPS_GET_PRINTERS - Get a list of all printers
  • +
  • CUPS_ADD_PRINTER - Add or modify a printer
  • +
  • CUPS_DELETE_PRINTER - Delete a printer
  • +
  • CUPS_GET_CLASSES - Get a list of all classes
  • +
  • CUPS_ADD_CLASS - Add or modify a class
  • +
  • CUPS_DELETE_CLASS - Delete a class
  • +
  • CUPS_ACCEPT_JOBS - Accept jobs on a printer or class
  • +
  • CUPS_REJECT_JOBS - Reject jobs on a printer or class
  • +
  • CUPS_SET_DEFAULT - Set the default destination
  • +
  • CUPS_GET_DEVICES - Get a list of all devices
  • +
  • CUPS_GET_PPDS - Get a list of all PPDs
  • +
  • CUPS_MOVE_JOB - Move a job to a new destination
  • +
+

Status Codes

+

Status codes are returned by all IPP requests.

+
    +
  • IPP_OK - Request completed with no errors
  • +
  • IPP_OK_SUBST - Request completed but some attribute + values were substituted
  • +
  • IPP_OK_CONFLICT - Request completed but some +attributes conflicted
  • +
  • IPP_BAD_REQUEST - The request was bad
  • +
  • IPP_FORBIDDEN - You don't have access to the resource
  • +
  • IPP_NOT_AUTHENTICATED - You are not authenticated for + the resource
  • +
  • IPP_NOT_AUTHORIZED - You not authorized to access the +resource
  • +
  • IPP_NOT_POSSIBLE - The requested operation cannot be + completed
  • +
  • IPP_TIMEOUT - A timeout occurred
  • +
  • IPP_NOT_FOUND - The resource was not found
  • +
  • IPP_GONE - The resource has gone away
  • +
  • IPP_REQUEST_ENTITY - The request was too large
  • +
  • IPP_REQUEST_VALUE - The request contained a value + that was unknown to the server
  • +
  • IPP_DOCUMENT_FORMAT - The document format is not + supported by the server
  • +
  • IPP_ATTRIBUTES - Required attributes are missing
  • +
  • IPP_URI_SCHEME - The URI scheme is not supported
  • +
  • IPP_CHARSET - The charset is not supported
  • +
  • IPP_CONFLICT - One or more attributes conflict
  • +
  • IPP_COMPRESSION_NOT_SUPPORTED - The specified + compression is not supported
  • +
  • IPP_COMPRESSION_ERROR - The compressed data contained +an error
  • +
  • IPP_DOCUMENT_FORMAT_ERROR - The document data + contained an error in it
  • +
  • IPP_DOCUMENT_ACCESS_ERROR - The remote document could +not be accessed
  • +
  • IPP_INTERNAL_ERROR - The server encountered an + internal error
  • +
  • IPP_OPERATION_NOT_SUPPORTED - The requested operation + is not supported
  • +
  • IPP_SERVICE_UNAVAILABLE - The requested service is +unavailable
  • +
  • IPP_VERSION_NOT_SUPPORTED - The IPP request version +is not supported
  • +
  • IPP_DEVICE_ERROR - The output device encountered an +error
  • +
  • IPP_TEMPORARY_ERROR - A temporary error occurred
  • +
  • IPP_NOT_ACCEPTING - The destination is not accepting + jobs
  • +
  • IPP_PRINTER_BUSY - The destination is busy
  • +
  • IPP_ERROR_JOB_CANCELLED - The requested job has been + cancelled
  • +
  • IPP_MULTIPLE_JOBS_NOT_SUPPORTED - The server does not +support multiple jobs
  • +
+

PPD Constants

+

PPD Format Version

+

The PPD_VERSION constant defines a floating point +number representing the newest format version that is supported by +CUPS, currently 4.3.

+

PPD User-Interface Types

+

Each printer option has a type associated with it:

+
    +
  • PPD_UI_BOOLEAN - The user can turn this option on or +off
  • +
  • PPD_UI_PICKONE - The user can choose one option value + to use.
  • +
  • PPD_UI_PICKMANY - The user can choose zero or more + option values.
  • +
+

PPD Sections

+

Some options must be output before others, or in different sections +of the output document. The ppd_section_t enumeration +defines which section the option must be output in:

+
    +
  • PPD_ORDER_ANY - The option can be output in any of + the document, page, or prolog sections of the document
  • +
  • PPD_ORDER_DOCUMENT - The option must be output in the +DocumentSetup section of the document
  • +
  • PPD_ORDER_EXIT - The option must be output before the +document
  • +
  • PPD_ORDER_JCL - The option must be output in the job +control section of the document
  • +
  • PPD_ORDER_PAGE - The option must be output in the + PageSetup section of the document
  • +
  • PPD_ORDER_PROLOG - The option must be output in the + Prolog section of the document
  • +
+

PPD Colorspaces

+

Each printer has a default colorspace:

+
    +
  • PPD_CS_CMYK - The printer uses CMYK colors by default
  • +
  • PPD_CS_CMY - The printer uses CMY colors by default
  • +
  • PPD_CS_GRAY - The printer uses grayscale by default
  • +
  • PPD_CS_RGB - The printer uses RGB colors by default
  • +
  • PPD_CS_RGBK - The printer uses RGBK colors by default
  • +
  • PPD_CS_N - The printer uses a DeviceN colorspace by +default
  • +
+

Raster Constants

+

Raster Sync Words

+

The CUPS_RASTER_SYNC and CUPS_RASTER_REVSYNC + constants define the standard sync words at the beginning of each CUPS +raster file.

+

Raster Stream Modes

+

The CUPS_RASTER_READ and CUPS_RASTER_WRITE + constants are used with the +cupsRasterOpen() function to specify a stream for reading or +writing.

+

Raster Boolean Constants

+

The CUPS_FALSE and CUPS_TRUE constants +represent boolean values in the page header.

+

Raster Jog Values

+

The cups_jog_t enumeration defines constants for the +Jog page device dictionary variable:

+
    +
  • CUPS_JOG_NONE - Do no jogging
  • +
  • CUPS_JOG_FILE - Jog pages after each file
  • +
  • CUPS_JOG_JOB - Jog pages after each job
  • +
  • CUPS_JOG_SET - Jog pages after each set of jobs
  • +
+

Raster Orientation Values

+

The cups_orient_t enumeration defines constants for the +Orientation page device dictionary variable:

+
    +
  • CUPS_ORIENT_0 - Portrait orientation
  • +
  • CUPS_ORIENT_90 - Landscape orientation
  • +
  • CUPS_ORIENT_180 - Reverse-portrait orientation
  • +
  • CUPS_ORIENT_270 - Reverse-landscape orientation
  • +
+

Raster CutMedia Values

+

The cups_cut_t enumeration defines constants for the +CutMedia page device dictionary variable:

+
    +
  • CUPS_CUT_NONE - Do no jogging
  • +
  • CUPS_CUT_FILE - Cut pages after each file
  • +
  • CUPS_CUT_JOB - Cut pages after each job
  • +
  • CUPS_CUT_SET - Cut pages after each set of jobs
  • +
  • CUPS_CUT_PAGE - Cut each page
  • +
+

Raster AdvanceMedia Values

+

The cups_advance_t enumeration defines constants for +the AdvanceMedia page device dictionary variable:

+
    +
  • CUPS_ADVANCE_NONE - Do no jogging
  • +
  • CUPS_ADVANCE_FILE - Advance media after each file
  • +
  • CUPS_ADVANCE_JOB - Advance media after each job
  • +
  • CUPS_ADVANCE_SET - Advance media after each set of +jobs
  • +
  • CUPS_ADVANCE_PAGE - Advance media for each page
  • +
+

Raster LeadingEdge Values

+

The cups_edge_t enumeration defines constants for the +LeadingEdge page device dictionary variable:

+
    +
  • CUPS_EDGE_TOP - The top of the media is the leading + edge
  • +
  • CUPS_EDGE_RIGHT - The right of the media is the +leading edge
  • +
  • CUPS_EDGE_BOTTOM - The bottom of the media is the + leading edge
  • +
  • CUPS_EDGE_LEFT - The left of the media is the leading + edge
  • +
+

Raster Color Order Values

+

The cups_order_t enumeration defines the possible color +value orderings:

+
    +
  • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK
  • +
  • CUPS_ORDER_BANDED - CCC MMM YYY KKK
  • +
  • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ...
  • +
+

Raster Colorspace Values

+

The cups_cspace_t enumeration defines the possible +colorspaces:

+
    +
  • CUPS_CSPACE_W - White (luminance)
  • +
  • CUPS_CSPACE_RGB - Red, green, blue
  • +
  • CUPS_CSPACE_RGBA - Red, green, blue, alpha
  • +
  • CUPS_CSPACE_K - Black
  • +
  • CUPS_CSPACE_CMY - Cyan, magenta, yellow
  • +
  • CUPS_CSPACE_YMC - Yellow, magenta, cyan
  • +
  • CUPS_CSPACE_CMYK - Cyan, magenta, yellow, black
  • +
  • CUPS_CSPACE_YMCK - Yellow, magenta, cyan, black
  • +
  • CUPS_CSPACE_KCMY - Black, cyan, magenta, yellow
  • +
  • CUPS_CSPACE_KCMYcm - Black, cyan, magenta, yellow, + light cyan, light magenta
  • +
  • CUPS_CSPACE_GMCK - Metallic yellow (gold), metallic +magenta, metallic cyan, black
  • +
  • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic +magenta, metallic cyan, metallic grey (silver)
  • +
  • CUPS_CSPACE_WHITE - White pigment (black as white +pigment)
  • +
  • CUPS_CSPACE_GOLD - Gold foil (black as gold foil)
  • +
  • CUPS_CSPACE_SILVER - Silver foil (black as silver +foil)
  • +
+

C - Structures

+

This appendix describes all of the structures that are defined by +the CUPS API.

+

Raster Structures

+

Raster Page Header

+

The raster page header consists of the PostScript page device +dictionary for the page: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
MediaClasschar[64]The media class name
MediaColorchar[64]The media color name
MediaTypechar[64]The media type name
OutputTypechar[64]The output type name
AdvanceDistanceunsignedThe distance to +advance the media in points
AdvanceMediacups_adv_tWhen to advance the +media
Collatecups_bool_tWhether or not to produce +collated copies
CutMediacups_cut_tWhen to cut the media
Duplexcups_bool_tWhether or not to print on +both sides of the paper
HWResolutionunsigned[2]The resolution of the +page image in pixels per inch; the HWResolution[0] represents the +horizontal resolution and HWResolution[1] represents the vertical +resolution
ImagingBoundingBoxunsigned[4]The bounding box +for the page in points; the elements represent the left, bottom, +right, and top coordinates of the imaged area (if 0 then the whole +page is imaged)
InsertSheetcups_bool_tWhether or not to +insert a sheet before this page
Jogcups_jog_tWhen to jog copies of the page
LeadingEdgecups_edge_tThe leading edge of the +page
Marginsunsigned[2]The lower-lefthand margin +of the page in points
ManualFeedcups_bool_tWhether or not to +manually feed the page
MediaPositionunsignedThe input slot number to +use
MediaWeightunsignedThe weight of the output +media in grams/m2
MirrorPrintcups_bool_tWhether or not to +mirror the print
NegativePrintcups_bool_tWhether or not to +invert the print
NumCopiesunsignedThe number of copies to +produce
Orientationcups_orient_tThe orientation of +the page image
OutputFaceUpcups_bool_tWhether or not to +output the page face up
PageSizeunsigned[2]The width and height of +the page in points
Separationscups_bool_tWhether or not to +output separations
TraySwitchcups_bool_tWhether or not to +automatically switch trays for the requested media size/type
Tumblecups_bool_tWhether or not to rotate the +back side of the page
cupsWidthunsignedThe width of the page image +in pixels
cupsHeightunsignedThe height of the page +image in pixels
cupsMediaTypeunsignedThe device-specific +media type code
cupsBitsPerColorunsignedThe number of bits +per color
cupsBitsPerPixelunsignedThe number of bits +per pixel
cupsBytesPerLineunsignedThe number of bytes +per line of image data
cupsColorOrdercups_order_tThe order of color +values
cupsColorSpacecups_cspace_tThe type of color +values
cupsCompressionunsignedThe device-specific +compression code
cupsRowCountunsignedThe device-specific row +count
cupsRowFeedunsignedThe device-specific row +feed
cupsRowStepunsignedThe device-specific row +step
+
+

+

D - Functions

+

This appendix provides a reference for all of the CUPS API +functions. + +

+

cupsAddOption()

+

Usage

+
+int
+cupsAddOption(const char *name,
+              const char *value,
+              int num_options,
+	      cups_option_t **options);
+
+

Arguments

+
+ + + + + + + +
ArgumentDescription
nameThe name of the option.
valueThe value of the option.
num_optionsNumber of options currently in the array.
optionsPointer to the options array.
+
+

Returns

+

The new number of options.

+

Description

+

cupsAddOption() adds an option to the specified array.

+

Example

+
+#include <cups.h>
+
+...
+
+/* Declare the options array */
+int           num_options;
+cups_option_t *options;
+
+/* Initialize the options array */
+num_options = 0;
+options     = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption("media", "letter", num_options, &options);
+num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
+
+

See Also

+ cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + + +

cupsCancelJob()

+

Usage

+
+int
+cupsCancelJob(const char *dest,
+              int job);
+
+

Arguments

+
+ + + + +
ArgumentDescription
destPrinter or class name
jobJob ID
+
+

Returns

+

1 on success, 0 on failure. On failure the error can be found by +calling cupsLastError().

+

Description

+

cupsCancelJob() cancels the specifies job.

+

Example

+
+#include <cups.h>
+
+cupsCancelJob("LaserJet", 1);
+
+

See Also

+

cupsLastError(), +cupsPrintFile() + +

+

cupsDoFileRequest()

+

Usage

+
+ipp_t *
+cupsDoFileRequest(http_t *http,
+                  ipp_t *request,
+                  const char *resource,
+		  const char *filename);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
filenameFile to send with POST request (NULL + pointer if none.)
+
+

Returns

+

IPP response data or NULL if the request fails. On +failure the error can be found by calling +cupsLastError().

+

Description

+

cupsDoFileRequest() does a HTTP POST request and +provides the IPP request and optionally the contents of a file to the +IPP server. It also handles resubmitting the request and performing +password authentication as needed.

+

Example

+
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_PRINT_FILE;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+             "attributes-charset", NULL, cupsLangEncoding(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+             "attributes-natural-language", NULL,
+             language != NULL ? language->language : "C");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+             NULL, "ipp://hostname/resource");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+             NULL, cupsUser());
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), +ippNew() + +

+

cupsDoRequest()

+

Usage

+
+ipp_t *
+cupsDoRequest(http_t *http,
+              ipp_t *request,
+              const char *resource);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
+
+

Returns

+

IPP response data or NULL if the request fails. On +failure the error can be found by calling +cupsLastError().

+

Description

+

cupsDoRequest() does a HTTP POST request and provides +the IPP request to the IPP server. It also handles resubmitting the +request and performing password authentication as needed.

+

Example

+
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+             "attributes-charset", NULL, cupsLangEncoding(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+             "attributes-natural-language", NULL,
+             language != NULL ? language->language : "C");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+             NULL, "ipp://hostname/resource");
+
+/* Do the request... */
+response = cupsDoRequest(http, request, "/resource");
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), +ippNew() + +

+

cupsFreeOptions()

+

Usage

+
+void
+cupsFreeOptions(int num_options,
+                cups_option_t *options);
+
+
+

Arguments

+
+ + + + +
ArgumentDescription
num_optionsNumber of options in array.
optionsPointer to options array.
+
+

Description

+

cupsFreeOptions() frees all memory associated with the +option array specified.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsGetOption(), cupsMarkOptions(), cupsParseOptions() + +

+

cupsGetClasses()

+

Usage

+
+int
+cupsGetClasses(char ***classes);
+
+

Arguments

+
+ + + +
ArgumentDescription
classesPointer to character pointer array.
+
+

Returns

+

The number of printer classes available.

+

Description

+

cupsGetClasses() gets a list of the available printer +classes. The returned array should be freed using the free() + when it is no longer needed.

+

Example

+
+#include <cups/cups.h>
+
+int  i;
+int  num_classes;
+char **classes;
+
+...
+
+num_classes = cupsGetClasses(
+
+...
+
+if (num_classes > 0)
+{
+  for (i = 0; i num_classes; i ++)
+    free(classes[i]);
+
+  free(classes);
+}
+
+

See Also

+

cupsGetDefault(), +cupsGetPrinters() + +

+

cupsGetDefault()

+

Usage

+
+const char *
+cupsGetDefault(void);
+
+

Returns

+

A pointer to the default destination.

+

Description

+

cupsGetDefault() gets the default destination printer +or class. The default destination is stored in a static string and will +be overwritten (usually with the same value) after each call.

+

Example

+
+#include <cups/cups.h>
+
+printf("The default destination is %s\n", cupsGetDefault());
+
+

See Also

+

cupsGetClasses(), +cupsGetPrinters() + +

+

cupsGetOption()

+

Usage

+
+const char *
+cupsGetOption(const char *name,
+              int num_options,
+              cups_option_t *options);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
nameThe name of the option.
num_optionsThe number of options in the array.
optionsThe options array.
+
+

Returns

+

A pointer to the option values or NULL if the option is +not defined.

+

Description

+

cupsGetOption() returns the first occurrence of the +named option. If the option is not included in the options array then a +NULL pointer is returned.

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+const char    *media;
+
+...
+
+media = cupsGetOption("media", num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsMarkOptions() +, cupsParseOptions() + +

+

cupsGetPassword()

+

Usage

+
+const char *
+cupsGetPassword(const char *prompt);
+
+

Arguments

+
+ + + +
ArgumentDescription
promptThe prompt to display to the user.
+
+

Returns

+

A pointer to the password that was entered or NULL if +no password was entered.

+

Description

+

cupsGetPassword() displays the prompt string and asks +the user for a password. The password text is not echoed to the user.

+

Example

+
+#include <cups/cups.h>
+
+char *password;
+
+...
+
+password = cupsGetPassword("Please enter a password:");
+
+

See Also

+

cupsServer(), +cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser() + + +

+

cupsGetPPD()

+

Usage

+
+const char *
+cupsGetPPD(const char *printer);
+
+

Arguments

+
+ + + +
ArgumentDescription
printerThe name of the printer.
+
+

Returns

+

The name of a temporary file containing the PPD file or NULL + if the printer cannot be located or does not have a PPD file.

+

Description

+

cupsGetPPD() gets a copy of the PPD file for the named +printer. The printer name can be of the form "printer" or +"printer@hostname".

+

You should remove (unlink) the PPD file after you are done using it. +The filename is stored in a static buffer and will be overwritten with +each call to cupsGetPPD().

+

Example

+
+#include <cups/cups.h>
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD("printer@hostname");
+
+...
+
+unlink(ppd);
+
+ + + +

cupsGetPrinters()

+

Usage

+
+int
+cupsGetPrinters(char ***printers);
+
+

Arguments

+
+ + + +
ArgumentDescription
printersPointer to character pointer array.
+
+

Returns

+

The number of printer printers available.

+

Description

+

cupsGetPrinters() gets a list of the available +printers. The returned array should be freed using the free() + when it is no longer needed.

+

Example

+
+#include <cups/cups.h>
+
+int  i;
+int  num_printers;
+char **printers;
+
+...
+
+num_printers = cupsGetPrinters(
+
+...
+
+if (num_printers > 0)
+{
+  for (i = 0; i num_printers; i ++)
+    free(printers[i]);
+
+  free(printers);
+}
+
+

See Also

+

cupsGetClasses(), +cupsGetDefault() + +

+

cupsLangDefault()

+

Usage

+
+const char *
+cupsLangDefault(void);
+
+

Returns

+

A pointer to the default language structure.

+

Description

+

cupsLangDefault() returns a language structure for the +default language. The default language is defined by the LANG + environment variable. If the specified language cannot be located then +the POSIX (English) locale is used.

+

Call cupsLangFree() to free any memory associated with +the language structure when you are done.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangEncoding(), +cupsLangFlush(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangEncoding()

+

Usage

+
+char *
+cupsLangEncoding(cups_lang_t *language);
+
+

Arguments

+
+ + + +
ArgumentDescription
languageThe language structure.
+
+

Returns

+

A pointer to the encoding string.

+

Description

+

cupsLangEncoding() returns the language encoding used +for the specified language, e.g. "iso-8859-1", "utf-8", etc.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangFlush(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangFlush()

+

Usage

+
+void
+cupsLangFlush(void);
+
+

Description

+

cupsLangFlush() frees all language structures that have +been allocated.

+

Example

+
+#include <cups/language.h>
+
+...
+
+cupsLangFlush();
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangFree()

+

Usage

+
+void
+cupsLangFree(cups_lang_t *language);
+
+

Arguments

+
+ + + +
ArgumentDescription
languageThe language structure to free.
+
+

Description

+

cupsLangFree() frees the specified language structure.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangGet(), cupsLangString() + +

+

cupsLangGet()

+

Usage

+
+cups_lang_t *
+cupsLangGet(const char *name);
+
+

Arguments

+
+ + + +
ArgumentDescription
nameThe name of the locale.
+
+

Returns

+

A pointer to a language structure.

+

Description

+

cupsLangGet() returns a language structure for the +specified locale. If the locale is not defined then the POSIX (English) +locale is substituted.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet("fr");
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangFree(), cupsLangString() + +

+

cupsLangString()

+

Usage

+
+char *
+cupsLangString(cups_lang_t *language,
+               int         message);
+
+

Arguments

+
+ + + + +
ArgumentDescription
languageThe language to query.
messageThe message number.
+
+

Returns

+

A pointer to the message string or NULL if the message +is not defined.

+

Description

+

cupsLangString() returns a pointer to the specified +message string in the specified language.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *s;
+...
+
+language = cupsLangGet("fr");
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangFree(), cupsLangGet() + +

+

cupsLastError()

+

Usage

+
+ipp_status_t
+cupsLastError(void);
+
+

Returns

+

An enumeration containing the last IPP error.

+

Description

+

cupsLastError() returns the last IPP error that +occurred. If no error occurred then it will return IPP_OK + or IPP_OK_CONFLICT.

+

Example

+
+#include <cups/cups.h>
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+
+

See Also

+

cupsCancelJob(), +cupsPrintFile() + +

+

cupsMarkOptions()

+

Usage

+
+int
+cupsMarkOptions(ppd_file_t *ppd,
+                int num_options,
+                cups_option_t *options);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
ppdThe PPD file to mark.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+
+

Returns

+

The number of conflicts found.

+

Description

+

cupsMarkOptions() marks options in the PPD file. It +also handles mapping of IPP option names and values to PPD option +names.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+ppd_file_t    *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsGetOption(), +cupsParseOptions() + +

+

cupsParseOptions()

+

Usage

+
+int
+cupsParseOptions(const char *arg,
+                 int num_options,
+                 cups_option_t **options);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
argThe string containing one or more options.
num_optionsThe number of options in the options array.
optionsA pointer to the options array pointer.
+
+

Returns

+

The new number of options in the array.

+

Description

+

cupsParseOptions() parses the specifies string for one +or more options of the form "name=value", "name", or "noname". It can +be called multiple times to combine the options from several strings.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options     = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsGetOption(), +cupsMarkOptions() + +

+

cupsPrintFile()

+

Usage

+
+int
+cupsPrintFile(const char    *printer,
+              const char    *filename,
+              const char    *title,
+	      int           num_options,
+	      cups_option_t *options);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
filenameThe file to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+
+

Returns

+

The new job ID number or 0 on error.

+

Description

+

cupsPrintFile() sends a file to the specified printer +or class for printing. If the job cannot be printed the error code can +be found by calling cupsLastError().

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+int           jobid;
+
+...
+
+jobid = cupsPrintFile("printer@hostname", "filename.ps", "Job Title",
+                      num_options, options);
+
+

See Also

+

cupsCancelJob(), +cupsLastError(), cupsPrintFiles() + + +

+

cupsPrintFiles()

+

Usage

+
+int
+cupsPrintFiles(const char    *printer,
+               int           num_files,
+               const char    **files,
+               const char    *title,
+	       int           num_options,
+	       cups_option_t *options);
+
+

Arguments

+
+ + + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
num_filesThe number of files to print.
filesThe files to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+
+

Returns

+

The new job ID number or 0 on error.

+

Description

+

cupsPrintFiles() sends multiple files to the specified +printer or class for printing. If the job cannot be printed the error +code can be found by calling cupsLastError().

+

Example

+
+#include <cups/cups.h>
+
+int           num_files;
+const char    *files[100];
+int           num_options;
+cups_option_t *options;
+int           jobid;
+
+...
+
+jobid = cupsPrintFiles("printer@hostname", num_files, files,
+                       "Job Title", num_options, options);
+
+

See Also

+

cupsCancelJob(), +cupsLastError(), cupsPrintFile() + +

+

cupsRasterClose()

+

Usage

+
+void
+cupsRasterClose(cups_raster_t *ras);
+
+

Arguments

+
+ + + +
ArgumentDescription
rasThe raster stream to close.
+
+

Description

+

cupsRasterClose() closes the specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+
+

See Also

+

cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterOpen()

+

Usage

+
+cups_raster_t *
+cupsRasterOpen(int fd,
+               cups_mode_t mode);
+
+

Arguments

+
+ + + + +
ArgumentDescription
fdThe file descriptor to use.
modeThe mode to use; CUPS_RASTER_READ or + CUPS_RASTER_WRITE.
+
+

Returns

+

A pointer to a raster stream or NULL if there was an +error.

+

Description

+

cupsRasterOpen() opens a raster stream for reading or +writing.

+

Example

+
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+
+

See Also

+

cupsRasterClose(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterReadHeader()

+

Usage

+
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+                     cups_page_header_t *header);
+
+

Arguments

+
+ + + + +
ArgumentDescription
rasThe raster stream to read from.
headerA pointer to a page header structure to read +into.
+
+

Returns

+

1 on success, 0 on EOF or error.

+

Description

+

cupsRasterReadHeader() reads a page header from the +specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterReadPixels()

+

Usage

+
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+                     unsigned char *pixels,
+		     unsigned length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
rasThe raster stream to read from.
pixelsThe pointer to a pixel buffer.
lengthThe number of bytes of pixel data to read.
+
+

Returns

+

The number of bytes read or 0 on EOF or error.

+

Description

+

cupsRasterReadPixels() reads pixel data from the +specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterWriteHeader()

+

Usage

+
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+                      cups_page_header_t *header);
+
+

Arguments

+
+ + + + +
ArgumentDescription
rasThe raster stream to write to.
headerA pointer to the page header to write.
+
+

Returns

+

1 on success, 0 on error.

+

Description

+

cupsRasterWriteHeader() writes the specified page +header to a raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + +

+

cupsRasterWritePixels()

+

Usage

+
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+                      unsigned char *pixels,
+		      unsigned length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
rasThe raster stream to write to.
pixelsThe pixel data to write.
lengthThe number of bytes to write.
+
+

Returns

+

The number of bytes written.

+

Description

+

cupsRasterWritePixels() writes the specified pixel data +to a raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + +

+

cupsServer()

+

Usage

+
+const char *
+cupsServer(void);
+
+

Returns

+

A pointer to the default server name.

+

Description

+

cupsServer() returns a pointer to the default server +name. The server name is stored in a static location and will be +overwritten with every call to cupsServer()

+

The default server is determined from the following locations:

+
    +
  1. The CUPS_SERVER environment variable,
  2. +
  3. The ServerName directive in the client.conf + file,
  4. +
  5. The default host, "localhost".
  6. +
+

Example

+
+#include <cups/cups.h>
+
+const char *server;
+
+server = cupsServer();
+
+

See Also

+

cupsGetPassword(), +cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser() + + +

+

cupsSetPasswordCB()

+

Usage

+
+void
+cupsSetPasswordCB(const char *(*cb)(const char *prompt));
+
+

Arguments

+
+ + + +
ArgumentDescription
cbThe password callback function.
+
+

Description

+

cupsSetPasswordCB() sets the callback function to use +when asking the user for a password. The callback function must accept +a single character string pointer (the prompt string) and return +NULL if the user did not enter a password string or a pointer to +the password string otherwise.

+

Example

+
+#include <cups/cups.h>
+
+const char *
+my_password_cb(const char *prompt)
+{
+  return (getpass(prompt));
+}
+
+...
+
+char *password;
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+password = cupsGetPassword("Please enter a password:");
+
+

See Also

+

cupsServer(), +cupsSetServer(), cupsSetUser(), +cupsUser() + +

+

cupsSetServer()

+

Usage

+
+void
+cupsSetServer(const char *server);
+
+

Arguments

+
+ + + +
ArgumentDescription
serverThe default server to use.
+
+

Description

+

cupsSetServer() sets the default server to use for the +CUPS API. If the server argument is NULL, the +default server is used.

+

Example

+
+#include <cups/cups.h>
+
+cupsSetServer("foo.bar.com");
+
+

See Also

+

cupsServer(), +cupsSetPasswordCB(), cupsSetUser(), +cupsUser() + +

+

cupsSetUser()

+

Usage

+
+void
+cupsSetUser(const char *user);
+
+

Arguments

+
+ + + +
ArgumentDescription
userThe user name string to use.
+
+

Description

+

cupsSetUser() sets the default user name for +authentication. If the user argument is NULL + then the current login user is used.

+

Example

+
+#include <cups/cups.h>
+
+...
+
+cupsSetUser("root");
+
+

See Also

+

cupsServer(), +cupsSetPasswordCB(), cupsSetServer(), cupsUser() + +

+

cupsTempFile()

+

Usage

+
+char *
+cupsTempFile(char *filename,
+             int length);
+
+

Arguments

+
+ + + + +
ArgumentDescription
filenameThe character string to hold the temporary +filename.
lengthThe size of the filename string in bytes.
+
+

Returns

+

A pointer to filename.

+

Description

+

cupsTempFile() generates a temporary filename for the +/var/tmp directory or the directory specified by the TMPDIR + environment variable.

+

Example

+
+#include <cups/cups.h>
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+
+ + + +

cupsUser()

+

Usage

+
+const char *
+cupsUser(void);
+
+

Returns

+

A pointer to the current username or NULL if the user +ID is undefined.

+

Description

+

cupsUser() returns the name associated with the current +user ID as reported by the getuid() system call.

+

Example

+
+#include <cups/cups.h>
+
+const char *user;
+
+user = cupsUser();
+
+

See Also

+

cupsGetPassword(), +cupsServer() + +

+

httpBlocking()

+

Usage

+
+void httpBlocking(http_t *http, int blocking)
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
blocking0 if the connection should be non-blocking, 1 +if it should be blocking
+
+

Description

+

The httpBlocking() function sets the blocking mode for +the HTTP connection. By default HTTP connections will block (stop) the +client program until data is available or can be sent to the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+http = httpConnect("server", port);
+httpBlocking(http, 0);
+
+

See Also

+ httpCheck(), +httpConnect() + + +

httpCheck()

+

Usage

+
+int httpCheck(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Returns

+

0 if there is no data pending, 1 otherwise.

+

Description

+

The httpCheck() function checks to see if there is any +data pending on an HTTP connection.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+if (httpCheck(http))
+{
+  ... do something ...
+}
+
+

See Also

+ httpBlocking(), +httpConnect(), httpGets() +, httpRead() + + +

httpClearFields()

+

Usage

+
+void httpClearFields(http_t *http)
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Description

+

The httpClearFields() function clears all HTTP request +fields for the HTTP connection.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpClearFields(http);
+
+

See Also

+ httpConnect(), +httpGetField(), +httpSetField() + + +

httpClose()

+

Usage

+
+void httpClose(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Description

+

The httpClose() function closes an active HTTP +connection.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpClose(http);
+
+

See Also

+ httpConnect() + + +

httpConnect()

+

Usage

+
+http_t *httpConnect(const char *hostname, int port);
+
+

Arguments

+
+ + + + +
ArgumentDescription
hostnameThe name or IP address of the server to +connect to
portThe port number to use
+
+

Returns

+

A pointer to a HTTP connection structure or NULL if the connection +could not be made.

+

Description

+

The httpConnect() function opens a HTTP connection to +the specified server and port.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+
+

See Also

+ httpClose(), +httpGet(), httpGets(), httpPost(), +httpRead(), httpWrite() + + +

httpDecode64()

+

Usage

+
+char *httpDecode64(char *out, const char *in);
+
+

Arguments

+
+ + + + +
ArgumentDescription
outThe output string
inThe input string
+
+

Returns

+

A pointer to the decoded string.

+

Description

+

The httpDecode64() function decodes a base-64 encoded +string to the original string.

+

Example

+
+#include <cups/http.h>
+
+char encoded_string[255];
+char original_string[255];
+
+httpDecode64(original_string, encoded_string);
+
+

See Also

+ httpEncode64() + + +

httpDelete()

+

Usage

+
+int httpDelete(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to delete
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpDelete() function sends a HTTP DELETE request +to the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpEncode64()

+

Usage

+
+char *httpEncode64(char *out, const char *in);
+
+

Arguments

+
+ + + + +
ArgumentDescription
outThe output string
inThe input string
+
+

Returns

+

A pointer to the encoded string.

+

Description

+

The httpEncode64() function decodes a base-64 encoded +string to the original string.

+

Example

+
+#include <cups/http.h>
+
+char encoded_string[255];
+char original_string[255];
+
+httpEncode64(encoded_string, original_string);
+
+

See Also

+ httpDecode64() + + +

httpError()

+

Usage

+
+int httpError(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Returns

+

The last error that occurred or 0 if no error has occurred.

+

Description

+

The httpError() function returns the last error that +occurred on the HTTP connection.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+if (httpError(http))
+{
+  ... show an error message ...
+}
+
+

See Also

+ httpConnect() + + +

httpFlush()

+

Usage

+
+void httpFlush(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Description

+

The httpFlush() function flushes any remaining data +left from a GET or POST operation.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpFlush(http);
+
+

See Also

+ httpConnect(), + + +

httpGet()

+

Usage

+
+int httpGet(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to get
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpGet() function sends a HTTP GET request to the +server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpGets()

+

Usage

+
+char *httpGets(char *line, int length, http_t *http)
+
+

Arguments

+
+ + + + + +
ArgumentDescription
lineThe string to fill with a line from the HTTP +connection
lengthThe maximum length of the string
httpThe HTTP connection
+
+

Returns

+

A pointer to the string or NULL if no line could be retrieved.

+

Description

+

The httpGets() function is used to read a request line +from the HTTP connection. It is not normally used by a client program.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+char line[1024];
+
+if (httpGets(line, sizeof(line), http))
+{
+  ... process the line ...
+}
+
+

See Also

+ httpConnect(), +httpUpdate() + + +

httpGetDateString()

+

Usage

+
+const char *httpGetDateString(time_t time)
+
+

Arguments

+
+ + + +
ArgumentDescription
timeThe UNIX date/time value
+
+

Returns

+

A pointer to a static string containing the HTTP date/time string +for the specified UNIX time value.

+

Description

+

The httpGetDateString() function generates a date/time +string suitable for HTTP requests from a UNIX time value.

+

Example

+
+#include <cups/http.h>
+
+puts(httpGetDateString(time(NULL)));
+
+

See Also

+ httpGetDateTime() + + +

httpGetDateTime()

+

Usage

+
+time_t httpGetDateTime(const char *date)
+
+

Arguments

+
+ + + +
ArgumentDescription
dateThe HTTP date/time string
+
+

Returns

+

A UNIX time value.

+

Description

+

The httpGetDateTime() function converts a HTTP +date/time string to a UNIX time value.

+

Example

+
+#include <cups/http.h>
+
+printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
+
+

See Also

+ httpGetDateString() + + +

httpGetField()

+

Usage

+
+const char *httpGetField(http_t *http, http_field_t field);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
fieldThe HTTP field
+
+

Returns

+

A pointer to the field value string.

+

Description

+

The httpGetField() function returns the current value +for the specified HTTP field.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
+
+

See Also

+ httpConnect(), +httpSetField() + + +

httpHead()

+

Usage

+
+int httpHead(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to head
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpHead() function sends a HTTP HEAD request to +the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpHead(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpInitialize()

+

Usage

+
+void httpInitialize(void);
+
+

Description

+

The httpInitialize() function initializes the +networking code as needed by the underlying platform. It is called +automatically by the httpConnect() function.

+

Example

+
+#include <cups/http.h>
+
+httpInitialize();
+
+

See Also

+ httpConnect() + + +

httpOptions()

+

Usage

+
+int httpOptions(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to check for options
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpOptions() function sends a HTTP OPTIONS request +to the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpOptions(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpPost()

+

Usage

+
+int httpPost(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to post to
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpPost() function sends a HTTP POST request to +the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpPost(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpPrintf()

+

Usage

+
+int httpPrintf(http_t *http, const char *format, ...);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
formatA printf-style format string
+
+

Returns

+

The number of bytes written.

+

Description

+

The httpPrintf() function sends a formatted string to +the HTTP connection. It is normally only used by the CUPS API and +scheduler.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpPrintf(http, "GET / HTTP/1.1 \r\n");
+
+

See Also

+ httpConnect() + + +

httpPut()

+

Usage

+
+int httpPut(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to put
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpPut() function sends a HTTP PUT request to the +server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpRead()

+

Usage

+
+int httpRead(http_t *http, char *buffer, int length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
httpThe HTTP connection
bufferThe buffer to read into
lengthThe number of bytes to read
+
+

Returns

+

The number of bytes read or -1 on error.

+

Description

+

The httpRead() function reads data from the HTTP +connection, possibly the result of a GET or POST request.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+char buffer[1024];
+int  bytes;
+
+httpGet(http, "/");
+while (httpUpdate(http) != HTTP_CONTINUE);
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+  buffer[bytes] = '\0';
+  fputs(buffer, stdout);
+}
+
+

See Also

+ httpConnect(), +httpWrite() + + +

httpReconnect()

+

Usage

+
+int httpReconnect(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpReconnect() function reconnects to the HTTP +server. This is usually done automatically if the HTTP functions detect +that the server connection has terminated.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpReconnect(http);
+
+

See Also

+ httpConnect() + + +

httpSeparate()

+

Usage

+
+void httpSeparate(const char *uri, char *method,
+                  char *username, char *host, int *port,
+                  char *resource);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
uriThe URI to separate
methodThe method (scheme) of the URI
usernameThe username (and password) portion of the +URI, if any
hostThe hostname portion of the URI, if any
portThe port number for the URI, either as specified +or as default for the method/scheme
resourceThe resource string, usually a filename on the +server
+
+

Description

+

The httpSeparate() function separates the specified URI +into its component parts. The method, username, hostname, and resource +strings should be at least HTTP_MAX_URI characters long to +avoid potential buffer overflow problems.

+

Example

+
+char uri[HTTP_MAX_URI];
+char method[HTTP_MAX_URI];
+char username[HTTP_MAX_URI];
+char host[HTTP_MAX_URI];
+char resource[HTTP_MAX_URI];
+int port;
+
+httpSeparate(uri, method, username, host, &port, resource);
+
+

See Also

+ httpConnect() + + +

httpSetField()

+

Usage

+
+void httpSetField(http_t *http, http_field_t field, const char *value);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
httpThe HTTP connection
fieldThe HTTP field
valueThe string value for the field
+
+

Description

+

The httpSetField() function sets the current value for +the specified HTTP field.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpSetField(http, HTTP_FIELD_AUTHORIZATION, "Basic dfdr34453454325"));
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+

See Also

+ httpConnect(), +httpGetField() + + +

httpTrace()

+

Usage

+
+int httpTrace(http_t *http, const char *uri);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to trace
+
+

Returns

+

0 on success, non-zero on failure.

+

Description

+

The httpTrace() function sends a HTTP TRACE request to +the server.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+
+httpTrace(http, "/some/uri");
+
+

See Also

+ httpConnect(), +httpSetField(), +httpUpdate() + + +

httpUpdate()

+

Usage

+
+http_status_t httpUpdate(http_t *http);
+
+

Arguments

+
+ + + +
ArgumentDescription
httpThe HTTP connection
+
+

Returns

+

The HTTP status of the current request.

+

Description

+

The httpUpdate() function updates the current request +status. It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or +TRACE request to finalize the HTTP request and retrieve the request +status.

+

Since proxies and the current blocking mode can cause the request to +take longer, programs should continue calling httpUpdate() + until the return status is not the constant value HTTP_CONTINUE +.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+http_status_t status;
+
+httpGet(http, "/some/uri");
+while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+printf("Request status is %d\n", status);
+
+

See Also

+ httpConnect(), +httpDelete(), httpGet() +, httpHead(), +httpOptions(), httpPost() +, httpPut(), +httpTrace() + + +

httpWrite()

+

Usage

+
+int httpWrite(http_t *http, char *buffer, int length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
httpThe HTTP connection
bufferThe buffer to read into
lengthThe number of bytes to read
+
+

Returns

+

The number of bytes read or -1 on error.

+

Description

+

The httpWrite() function reads data from the HTTP +connection, possibly the result of a GET or POST request.

+

Example

+
+#include <cups/http.h>
+
+http_t *http;
+FILE *fp;
+char buffer[1024];
+int  bytes;
+
+httpPost(http, "/");
+
+while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+  httpWrite(http, buffer, bytes);
+
+while (httpUpdate(http) != HTTP_CONTINUE);
+
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+  buffer[bytes] = '\0';
+  fputs(buffer, stdout);
+}
+
+

See Also

+ httpConnect(), +httpRead() + + +

ippAddBoolean()

+

Usage

+
+ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
+                               const char *name, char value);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
valueThe boolean value
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddBoolean() function adds a single boolean +attribute value to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
+
+

See Also

+ ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddBooleans()

+

Usage

+
+ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
+                                const char *name, int num_values,
+                                const char *values);
+
+

Arguments

+
+ + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of values
valuesThe boolean values
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddBooleans() function adds one or more boolean +attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values + false values is created.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+char values[10];
+
+ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
+
+

See Also

+ ippAddBoolean(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddDate()

+

Usage

+
+ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
+                            const char *name, ipp_uchar_t *value);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
valueThe date value
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddDate() function adds a single date-time +attribute value to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute", 
+           ippTimeToDate(time(NULL));
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings(), +ippTimeToDate() + + +

ippAddInteger()

+

Usage

+
+ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
+                               ipp_tag_t tag, const char *name,
+                               int value);
+
+

Arguments

+
+ + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of integer value (IPP_TAG_INTEGER or +IPP_TAG_ENUM)
nameThe name of attribute
valueThe integer value
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddInteger() function adds a single integer +attribute value to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddIntegers()

+

Usage

+
+ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
+                                ipp_tag_t tag, const char *name,
+                                int num_values, const int *values);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of integer value (IPP_TAG_INTEGER or +IPP_TAG_ENUM)
nameThe name of attribute
num_valuesThe number of values
valuesThe integer values
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddIntegers() function adds one or more integer +attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values + 0 values is created.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int values[100];
+
+ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddRange()

+

Usage

+
+ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
+                             const char *name, int low,
+                             int high);
+
+

Arguments

+
+ + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
lowThe lower value
highThe higher value
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddRange() function adds a single range +attribute value to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddRanges()

+

Usage

+
+ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
+                              const char *name, int num_values,
+                              const int *lows, const int *highs);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of range values
lowsThe lower values
highsThe higher values
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddRanges() function adds one or more range +attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values + 0,0 ranges is created.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int lows[2];
+int highs[2];
+
+ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddResolution()

+

Usage

+
+ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
+                                  const char *name, int xres,
+                                  int yres, ipp_res_t units);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
xresThe horizontal resolution
yresThe vertical resolution
unitsThe resolution units
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddResolution() function adds a single +resolution attribute value to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
+              720, 720, IPP_RES_PER_INCH);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddResolutions()

+

Usage

+
+ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
+                                   const char *name, int num_values,
+                                   const int *xres, const int *yres,
+                                   const ipp_res_t *units);
+
+

Arguments

+
+ + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of resolution values
xresThe horizontal resolutions
yresThe vertical resolutions
unitsThe resolution units
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddResolutions() function adds one or more +resolution attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 resolutions is created.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int xres[5];
+int yres[5];
+ipp_res_t units[5];
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolutions-supported",
+              5, xres, yres, units);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddSeparator()

+

Usage

+
+ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
+
+

Arguments

+
+ + + +
ArgumentDescription
ippThe IPP request
+
+

Returns

+

A pointer to the new separator or NULL if the separator could not be +created.

+

Description

+

The ippAddSeparator() function adds a group separator +to the specified IPP request.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddSeparator(ipp);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddString(), +ippAddStrings() + + +

ippAddString()

+

Usage

+
+ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
+                              ipp_tag_t tag, const char *name,
+                              const char *charset, const char *value);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of string value
nameThe name of attribute
charsetThe character set for the string
valueThe string value
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddString() function adds a single string +attribute value to the specified IPP request. For IPP_TAG_NAMELANG + and IPP_TAG_TEXTLANG strings, the charset value is +provided with the string to identify the string encoding used. +Otherwise the charset value is ignored.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+             NULL, "abc123");
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddStrings() + + +

ippAddStrings()

+

Usage

+
+ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
+                               ipp_tag_t tag, const char *name,
+                               int num_values, const char *charset,
+                               const char **values);
+
+

Arguments

+
+ + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of string value
nameThe name of attribute
num_valuesThe number of strings
charsetThe character set for the strings
valuesThe string values
+
+

Returns

+

A pointer to the new attribute or NULL if the attribute could not be +created.

+

Description

+

The ippAddStrings() function adds one or more string +attribute values to the specified IPP request. For +IPP_TAG_NAMELANG and IPP_TAG_TEXTLANG strings, the +charset value is provided with the strings to identify the string +encoding used. Otherwise the charset value is ignored. If the +values pointer is NULL then an array of +num_values NULL strings is created.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+char *values[2] = { "one", "two" };
+
+ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
+              2, NULL, values);
+
+

See Also

+ ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString() + + +

ippDateToTime()

+

Usage

+
+time_t ippDateToTime(const ipp_uchar_t date[11]);
+
+

Arguments

+
+ + + +
ArgumentDescription
dateThe IPP date-time value
+
+

Returns

+

A UNIX time value.

+

Description

+

The ippDateToTime() function converts an IPP date-time +value to a UNIX time value.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_uchar_t date[11];
+
+printf("UNIX time is %d\n", ippDateToTime(date));
+
+

See Also

+ ippTimeToDate() + + +

ippDelete()

+

Usage

+
+void ippDelete(ipp_t *ipp);
+
+

Arguments

+
+ + + +
ArgumentDescription
ippThe IPP request or response
+
+

Description

+

The ippDelete() function deletes all memory used by an +IPP request or response.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippDelete(ipp);
+
+

See Also

+ ippNew() + + +

ippFindAttribute()

+

Usage

+
+ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t tag);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
ippThe IPP request or response
nameThe name of the attribute
tagThe required value tag for the attribute or + IPP_TAG_ZERO for any type of value.
+
+

Returns

+

A pointer to the first occurrence of the requested attribute, or +NULL if it was not found.

+

Description

+

ippFindAttribute() finds the first occurrence of the +named attribute. The tag parameter restricts the search to +a specific value type - use IPP_TAG_ZERO to find any value +with the name.

+

The value tags IPP_TAG_NAME and IPP_TAG_TEXT + match the name/text values with or without the language code.

+

Example

+
+ipp_attribute_t *attr;
+
+attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
+
+

See Also

+ cupsDoFileRequest(), +cupsDoRequest(), ippDelete() +, ippNew() + + +

ippLength()

+

Usage

+
+int ippLength(ipp_t *ipp);
+
+

Arguments

+
+ + + +
ArgumentDescription
ippThe IPP request or response
+
+

Returns

+

The total encoded length of the IPP request or response in bytes.

+

Description

+

ippLength() returns the length of the IPP request or +response in bytes.

+

Example

+
+printf("The length of the response is %d bytes.\n", ippLength(response));
+
+

See Also

+ ippDelete(), +ippNew() + + +

ippNew()

+

Usage

+
+ipp_t *ippNew(void);
+
+

Returns

+

A pointer to a new IPP request or response.

+

Description

+

The ippNew() function creates a new IPP request or +response.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ipp = ippNew();
+
+

See Also

+ ippDelete() + + +

ippPort()

+

Usage

+
+int ippPort(void);
+
+

Returns

+

The default TCP/IP port number for IPP requests.

+

Description

+

The ippPort() function returns the default IPP port +number for requests.

+

Example

+
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+
+

See Also

+ cupsServer(), +ippSetPort() + + +

ippRead()

+

Usage

+
+ipp_state_t ippRead(http_t *http, ipp_t *ipp);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
ippThe IPP request or response
+
+

Returns

+

The current read state.

+

Description

+

The ippRead() function reads IPP attributes from the +specified HTTP connection. Programs should continue calling +ippRead() until IPP_ERROR or IPP_DATA + is returned.

+

Example

+
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+
+while ((status = ippRead(http, ipp)) != IPP_ERROR)
+  if (status == IPP_DATA)
+    break;
+
+if (status == IPP_DATA)
+{
+  ... read additional non-IPP data using httpRead() ...
+}
+
+

See Also

+ ippWrite() + + +

ippSetPort()

+

Usage

+
+void
+ippSetPort(int port);
+
+

Arguments

+
+ + + +
ArgumentDescription
portThe port number to use
+
+

Description

+

The ippSetPort() function sets the default IPP port +number for requests.

+

Example

+
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+...
+
+ippSetPort(8631);
+
+

See Also

+ ippPort() + + +

ippTimeToDate()

+

Usage

+
+ipp_uchar_t *ippTimeToDate(time_t time);
+
+

Arguments

+
+ + + +
ArgumentDescription
timeThe UNIX time value
+
+

Returns

+

A static pointer to an IPP date-time value.

+

Description

+

The ippTimeToDate() function converts a UNIX time to an +IPP date-time value.

+

Example

+
+#include <cups/ipp.h>
+
+ipp_uchar_t *date;
+
+date = ippTimeToDate(time(NULL));
+
+

See Also

+ ippDateToTime() + + +

ippWrite()

+

Usage

+
+ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
+
+

Arguments

+
+ + + + +
ArgumentDescription
httpThe HTTP connection
ippThe IPP request or response
+
+

Returns

+

The current write state.

+

Description

+

The ippWrite() function writes IPP attributes to the +specified HTTP connection. Programs should continue calling +ippWrite() until IPP_ERROR or IPP_DATA + is returned.

+

Example

+
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+... add attributes ...
+
+while ((status = ippWrite(http, ipp)) != IPP_ERROR)
+  if (status == IPP_DATA)
+    break;
+
+if (status == IPP_DATA)
+{
+  ... read additional non-IPP data using httpWrite() ...
+}
+
+

See Also

+ ippRead() + + +

ppdClose()

+

Usage

+
+void ppdClose(ppd_file_t *ppd);
+
+

Arguments

+
+ + + +
ArgumentDescription
ppdThe PPD file
+
+

Description

+

The ppdClose() function frees all memory associated +with the PPD file.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdClose(ppd);
+
+

See Also

+ ppdOpen(), +ppdOpenFd(), ppdOpenFile() + + + +

ppdConflicts()

+

Usage

+
+int ppdConflicts(ppd_file_t *ppd);
+
+

Arguments

+
+ + + +
ArgumentDescription
ppdThe PPD file
+
+

Returns

+

The number of option conflicts in the file.

+

Description

+

The ppdConflicts() function returns the number of +conflicts with the currently selected options.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("%d conflicts\n", ppdConflicts(ppd));
+
+

See Also

+ cupsMarkOptions(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdEmit()

+

Usage

+
+int ppdEmit(ppd_file_t *ppd, FILE *file, ppd_section_t section);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
ppdThe PPD file
fileThe file to write to
sectionThe option section to write
+
+

Returns

+

0 on success, -1 on error.

+

Description

+

The ppdEmit() function sends printer-specific option +commands to the specified file.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+

See Also

+ ppdEmitFd() + + +

ppdEmitFd()

+

Usage

+
+int ppdEmitFd(ppd_file_t *ppd, int fd, ppd_section_t section);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
ppdThe PPD file
fdThe file descriptor to write to
sectionThe option section to write
+
+

Returns

+

0 on success, -1 on error.

+

Description

+

The ppdEmitFd() function sends printer-specific option +commands to the specified file descriptor.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
+
+

See Also

+ ppdEmit() + + +

ppdFindChoice()

+

Usage

+
+ppd_choice_t *ppdFindChoice(ppd_option_t *option, const char *choice);
+
+

Arguments

+
+ + + + +
ArgumentDescription
optionA pointer to the option
choiceThe name of the choice
+
+

Returns

+

A pointer to the choice data or NULL if the choice does not exist.

+

Description

+

The ppdFindChoice() function returns a pointer to the +choice data for the specified option.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+ppd_choice_t *choice;
+
+option = ppdFindOption(ppd, "PageSize");
+choice = ppdFindChoice(option, "Letter");
+
+

See Also

+ ppdFindMarkedChoice(), ppdFindOption() + + +

ppdFindMarkedChoice()

+

Usage

+
+ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
+
+

Arguments

+
+ + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
+
+

Returns

+

A pointer to the choice data or NULL if the choice does not exist or +is not marked.

+

Description

+

The ppdFindMarkedChoice() function returns a pointer to +the marked choice data for the specified option.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_choice_t *choice;
+
+choice = ppdFindMarkedChoice(ppd, "PageSize");
+
+

See Also

+ ppdFindChoice(), +ppdFindOption() + + +

ppdFindOption()

+

Usage

+
+ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
+
+

Arguments

+
+ + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
+
+

Returns

+

A pointer to the option data or NULL if the option does not exist.

+

Description

+

The ppdFindOption() function returns a pointer to the +option data for the specified option.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+
+option = ppdFindOption(ppd, "PageSize");
+
+

See Also

+ ppdFindChoice(), +ppdFindMarkedChoice() + + +

ppdIsMarked()

+

Usage

+
+int ppdIsMarked(ppd_file_t *ppd, const char *keyword, char char *choice);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
choiceThe name of the option choice
+
+

Returns

+

1 if the choice is marked, 0 otherwise.

+

Description

+

The ppdIsMarked() function returns whether or not the +specified option choice is marked.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Letter size %s selected.\n",
+       ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
+
+

See Also

+ cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdMarkDefaults()

+

Usage

+
+void ppdMarkDefaults(ppd_file_t *ppd);
+
+

Arguments

+
+ + + +
ArgumentDescription
ppdThe PPD file
+
+

Description

+

The ppdMarkDefaults() function marks all of the default +choices in the PPD file.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkDefaults(ppd);
+
+

See Also

+ cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdMarkOption()

+

Usage

+
+int ppdMarkOption(ppd_file_t *ppd, const char *keyword, const char *choice);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
choiceThe name of the choice
+
+

Returns

+

The number of conflicts in the PPD file.

+

Description

+

The ppdMarkOption() function marks the specified option +choice.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkOption(ppd, "PageSize", "Letter");
+
+

See Also

+ cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdOpen()

+

Usage

+
+ppd_file_t *ppdOpen(FILE *file);
+
+

Arguments

+
+ + + +
ArgumentDescription
fileThe file to read from
+
+

Returns

+

A pointer to a PPD file structure or NULL if the PPD file could not +be read.

+

Description

+

The ppdOpen() function reads a PPD file from the +specified file into memory.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+FILE *file;
+
+file = fopen("filename.ppd", "rb");
+ppd = ppdOpen(file);
+fclose(file);
+
+

See Also

+ ppdClose(), +ppdOpenFd(), ppdOpenFile() + + + +

ppdOpenFd()

+

Usage

+
+ppd_file_t *ppdOpenFd(int fd);
+
+

Arguments

+
+ + + +
ArgumentDescription
fdThe file descriptor to read from
+
+

Returns

+

A pointer to a PPD file structure or NULL if the PPD file could not +be read.

+

Description

+

The ppdOpenFd() function reads a PPD file from the +specified file descriptor into memory.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+int        fd;
+
+fd = open("filename.ppd", O_RDONLY);
+ppd = ppdOpenFd(fd);
+close(fd);
+
+

See Also

+ ppdClose(), +ppdOpen(), ppdOpenFile() + + + +

ppdOpenFile()

+

Usage

+
+ppd_file_t *ppdOpenFile(const char *filename);
+
+

Arguments

+
+ + + +
ArgumentDescription
filenameThe name of the file to read from
+
+

Returns

+

A pointer to a PPD file structure or NULL if the PPD file could not +be read.

+

Description

+

The ppdOpenFile() function reads a PPD file from the +named file into memory.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile("filename.ppd");
+
+

See Also

+ ppdClose(), +ppdOpen(), ppdOpenFd() + + +

ppdPageLength()

+

Usage

+
+float ppdPageLength(ppd_file_t *ppd, const char *name);
+
+

Arguments

+
+ + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+
+

Returns

+

The length of the specified page size in points or 0 if the page +size does not exist.

+

Description

+

The ppdPageLength() function returns the page length of +the specified page size.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
+
+

See Also

+ ppdPageLength(), +ppdPageSize(), +ppdPageWidth() + + +

ppdPageSize()

+

Usage

+
+ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
+
+

Arguments

+
+ + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+
+

Returns

+

A pointer to the page size record of the specified page size in +points or NULL if the page size does not exist.

+

Description

+

The ppdPageSize() function returns the page size record +for the specified page size.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+
+size = ppdPageSize(ppd, "Letter");
+if (size != NULL)
+{
+  printf(" Width = %.0f\n", size->width);
+  printf("Length = %.0f\n", size->length);
+  printf("  Left = %.0f\n", size->left);
+  printf(" Right = %.0f\n", size->right);
+  printf("Bottom = %.0f\n", size->bottom);
+  printf("   Top = %.0f\n", size->top);
+}
+
+

See Also

+ ppdPageLength(), +ppdPageWidth() + + +

ppdPageWidth()

+

Usage

+
+float ppdPageWidth(ppd_file_t *ppd, const char *name);
+
+

Arguments

+
+ + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+
+

Returns

+

The width of the specified page size in points or 0 if the page size +does not exist.

+

Description

+

The ppdPageWidth() function returns the page width of +the specified page size.

+

Example

+
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
+
+

See Also

+ ppdPageLength(), +ppdPageSize() + diff --git a/doc/spm.pdf b/doc/spm.pdf new file mode 100644 index 0000000000000000000000000000000000000000..672132355ad5b3883ce9a4a0d78914cf236260ee GIT binary patch literal 590490 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�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 + + + + + CUPS Software Programmers Manual + + + +

Preface

+ +

This software programmers manual provides software +programming information for the Common UNIX Printing System +("CUPS") Version 1.1.7. + + + + +

Document Overview

+ +

This software programmers manual is organized into the following sections: + +

+ +

Notation Conventions

+ +

Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Example   Description
 
lpstat
+ lpstat(1)
   The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
 
/var
+ /usr/share/cups/data/testprint.ps
   File and directory names.
 
Request ID is Printer-123   Screen output.
 
lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
+ + +

Abbreviations

+ +The following abbreviations are used throughout this manual: + +
    +
    + +
    kb +
    Kilobytes, or 1024 bytes
      + +
    Mb +
    Megabytes, or 1048576 bytes
      + +
    Gb +
    Gigabytes, or 1073741824 bytes
      + +
    +
+ +

Other References

+ +
    +
    + +
    CUPS Software Administrators Manual + +
    An administration guide for the CUPS software.
      + +
    CUPS Software Users Manual + +
    An end-user guide for using the CUPS software.
      + +
    +
+ + + + + +

2 - The CUPS API

+ +

This chapter describes the CUPS Application Programmers Interface ("API"). + +

The CUPS API Library

+ +

The CUPS library provides a whole collection of interfaces needed to +support the internal needs of the CUPS software as well as the needs of +applications, filters, printer drivers, and backends. + +

Unlike the rest of CUPS, the CUPS API library is provided under the +GNU Library General Public License. This means that you can use the +CUPS API library in both proprietary and open-source programs. + +

Programs that use the CUPS API library typically will include the +<cups/cups.h> header file: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +jobid = cupsPrintFile("myprinter", "filename.ps", "title",
    +                      num_options, options);
    +
+ +

Use the -lcups compiler option when linking to the CUPS API +library: + +

    +cc -o program program.c -lcups ENTER
    +
+ +

Additional options and libraries may be required depending on the +operating system and the location of the CUPS API library. + +

Detecting the CUPS API Library in GNU Autoconf

+ +

GNU autoconf is a popular configuration tool used by many programs. +Add the following lines to your configure.in file to check +for the CUPS API library in your configuration script: + +

    +AC_CHECK_LIB(socket,socket,
    +if test "$uname" != "IRIX"; then
    +	LIBS="-lsocket $LIBS"
    +else
    +	echo "Not using -lsocket since you are running IRIX."
    +fi)
    +AC_CHECK_LIB(nsl,gethostbyaddr,
    +if test "$uname" != "IRIX"; then
    +	LIBS="-lnsl $LIBS"
    +else
    +	echo "Not using -lnsl since you are running IRIX."
    +fi)
    +
    +AC_CHECK_LIB(cups,httpConnect)
    +
+ +

Printing Services

+ +

The CUPS API library provides some basic printing services for applications +that need to print files. + +

Include Files

+ +

The include file used by all of these functions is +<cups/cups.h>: + +

    +#include <cups/cups.h>
    +
+ +

Printing a File

+ +

The CUPS API provides two functions for printing files. The first is +cupsPrintFile which prints a single named file: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +
    +...
    +
    +jobid = cupsPrintFile("name", "filename", "title", 0, NULL);
    +
+ +

The name string is the name of the printer or class to +print to. The filename string is the name of the file to +print. The title string is the name of the print job, e.g. +"Acme Word Document". + +

The return value is a unique ID number for the print job or 0 if there +was an error. + +

Printing Multiple Files

+ +

The second printing function is cupsPrintFiles: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int        jobid;
    +int        num_files;
    +const char *files[100];
    +...
    +
    +jobid = cupsPrintFiles("name", num_files, files, "title", 0, NULL);
    +
+ +

Instead of passing a filename string as with cupsPrintFile(), +you pass a file count (num_files) and filename pointer array +(files) for each file that you want to print. + +

As with cupsPrintFile(), the return value is a unique ID for +the print job. + +

Cancelling Jobs

+ +

The cupsCancelJob() function cancels a queued print job: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +int status;
    +...
    +
    +status = cupsCancelJob("name", jobid);
    +
+ +

The name string specifies the destination and is used +to determine the server to send the request to. The jobid +value is the integer returned from a previous cupsPrintFile() +or cupsPrintFiles() call. + +

cupsCancelJob() returns 1 if the job was +successfully cancelled and 0 if there was an error. + +

Getting the Available Printers and Classes

+ +

The cupsGetDests() function can be used to get a list +of the available printers, classes, and instances that a user has defined: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +...
    +
    +num_dests = cupsGetDests(&dests);
    +
+ +

Each destination is stored in a cups_dest_t structure which +defines the printer or class name, the instance name (if any), if it is the +default destination, and the default options the user has defined for the +destination: + +

    +typedef struct               /**** Destination ****/
    +{
    +  char          *name,       /* Printer or class name */
    +                *instance;   /* Local instance name or NULL */
    +  int           is_default;  /* Is this printer the default? */
    +  int           num_options; /* Number of options */
    +  cups_option_t *options;    /* Options */
    +} cups_dest_t;
    +
+ +

The destinations are sorted by name and instance for your convenience. +Once you have the list of available destinations, you can lookup a specific +destination using the cupsGetDest() function: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *mydest;
    +
    +...
    +
    +mydest = cupsGetDest("name", "instance", num_dests, dests);
    +
+ +

The name string is the printer or class name. You can pass +a value of NULL to get the default destination. + +

The instance string is the user-defined instance name. Pass +NULL to select the default instance, e.g. "name" instead of +"name/instance". + +

Printing with Options

+ +

All of the previous printing examples have passed 0 and +NULL for the last two arguments to the cupsPrintFile() +and cupsPrintFiles() functions. These last two arguments are the +number of options and a pointer to the option array: + +

    +int cupsPrintFile(const char *name, const char *filename, const char *title,
    +                  int num_options, cups_option_t *options);
    +int cupsPrintFiles(const char *name, int num_files, const char **files,
    +                   const char *title, int num_options,
    +		   cups_option_t *options);
    +
+ +

The cups_option_t structure holds each option and its value. +These are converted as needed and passed to the CUPS server when printing a +file. + +

The simplest way of handling options is to use the num_options +and options members of the cups_dest_t +structure described earlier: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int         jobid;
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *mydest;
    +
    +...
    +
    +mydest = cupsGetDest("name", "instance", num_dests, dests);
    +
    +jobid  = cupsPrintFile(mydest->name, "filename", "title",
    +                       mydest->num_options, mydest->options);
    +
+ +

This effectively uses the options a user has previous selected without a +lot of code. + +

Setting Printer Options

+ +

Options can also be set by your program using the cupsAddOption() +function: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +num_options = 0;
    +options     = NULL;
    +
    +...
    +
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +num_options = cupsAddOption("name", "value", num_options, &options);
    +
+ +

The name string is the name of the option, and the +value string is the value for that option. + +

Each call to cupsAddOption() returns the new number of +options. Since adding two options with the same name overwrites the +first value with the second, do not assume that calling +cupsAddOptions() 20 times will result in 20 options. + +

Call cupsFreeOptions once you are done using the options: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +cupsFreeOptions(num_options, options);
    +
+ +

Getting Errors

+ +

If any of the CUPS API printing functions returns an error, the reason for +that error can be found by calling cupsLastError() and +cupsErrorString(). cupsLastError() returns the +last IPP error code that was encountered. cupsErrorString() +converts the error code to a localized message string suitable for +presentation to the user: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +int jobid;
    +
    +...
    +
    +if (jobid == 0)
    +  puts(cupsErrorString(cupsLastError()));
    +
+ +

Passwords and Authentication

+ +

CUPS supports authentication of any request, including +submission of print jobs. The default mechanism for getting the +username and password is to use the login user and a password +from the console. + +

To support other types of applications, in particular +Graphical User Interfaces ("GUIs"), the CUPS API provides +functions to set the default username and to register a callback +function that returns a password string. + +

The cupsSetPasswordCB() +function is used to set a password callback in your program. Only one +function can be used at any time. + +

The cupsSetUser() function sets +the current username for authentication. This function can be called by +your password callback function to change the current username as needed. + +

The following example shows a simple password callback that gets a +username and password from the user: + +

    +#include <cups/cups.h>
    +
    +const char *
    +my_password_cb(const char *prompt)
    +{
    +  char	user[65];
    +
    +
    +  puts(prompt);
    +
    + /* Get a username from the user */
    +  printf("Username: ");
    +  if (fgets(user, sizeof(user), stdin) == NULL)
    +    return (NULL);
    +
    + /* Strip the newline from the string and set the user */
    +  user[strlen(user) - 1] = '\0';
    +
    +  cupsSetUser(user);
    +
    + /* Use getpass() to ask for the password... */
    +  return (getpass("Password: "));
    +}
    +
    +...
    +
    +cupsSetPasswordCB(my_password_cb);
    +
+ +

Similarly, a GUI interface could display the prompt string in a +window with input fields for the username and password. The username +should probably default to the value of +cupsUser() to make things easier +on the user. + +

PPD Services

+ +

CUPS includes functions to access and manipulate PostScript Printer +Description ("PPD") files that are used with the printer drivers in CUPS. + +

Each PPD file enumerates the available features provided by a +printer, including conflict information for specific options (e.g. +can't duplex output on envelopes.) + +

Include Files

+ +

Include the <cups/ppd.h> header file to use the PPD +functions: + +

    +#include <cups/ppd.h>
    +
+ +

This header file is also included by the +<cups/cups.h> header file. + +

Getting a PPD File for a Printer

+ +

The cupsGetPPD() function retrieves the PPD file for the +named printer or class: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +const char *filename;
    +
    +filename = cupsGetPPD("name");
    +
+ +

The name string is the name of the printer or class, including +the remote server name as appropriate (e.g. "printer@server".) + +

The return value is a pointer to a filename in static storage; this value +is overwritten with each call to cupsGetPPD(). If the printer +or class does not exist, a NULL pointer will be returned. + +

Loading a PPD File

+ +

The ppdOpenFile() function "opens" a PPD file and loads it +into memory: + +

    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +ppd = ppdOpenFile("filename");
    +
+ +

The filename string is the name of the file to load, such as +the value returned by the cupsGetPPD() function. + +

The return value is a pointer to a structure describing the contents of the +PPD file or NULL if the PPD file could not be read. + +

Freeing PPD File Information

+ +

Once you are done using a PPD file, call the ppdClose() function +to free all memory that has been used: + +

    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +...
    +
    +ppdClose(ppd);
    +
+ +

The PPD File Structure

+ +

Each PPD file contains a number of capability attributes, printer options, +and conflict definitions. The page size options also include the physical +margins for the printer and the minimum and maximum sizes for the printer. +All of this information is stored in the ppd_file_t structure. + +

Capabilities

+ +

Each PPD file contains a number of informational attributes that +describe the capabilities of the printer. These are provided in the +ppd_file_t structure in the following members: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
accurate_screensint1 = supports accurate screens
color_deviceint1 = color device
colorspaceppd_cs_tDefault colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY, + PPD_CS_RGB, PPD_CS_RGBK, PPD_CS_N
contone_onlyint1 = printer is continuous tone only
num_emulations
+ emulations
int
+ ppd_emul_t *
Emulations supported by the printer
flip_duplexint1 = need to flip odd pages when duplexing
num_fonts
+ fonts
int
+ char **
The fonts available on the printer.
jcl_begin
+ jcl_ps
+ jcl_end
char *Job Control Language commands for PostScript output
landscapeintLandscape orientation, -90 or 90 degrees
lang_encodingchar *The character used for the option strings
lang_versionchar *The language used for the options strings (English, French, etc.)
language_levelintPostScript language level, 1 to 3
manual_copiesint1 = Copies are done manually
model_numberintDriver-specific model number.
patcheschar *Patch commands to send to the printer
manufacturerchar *The Manufacturer attribute from the PPD file, if any
modelnamechar *The ModelName attribute from the PPD file
nicknamechar *The NickName attribute from the PPD file, if any
productchar *The Product attribute from the PPD file, if any
shortnicknamechar *The ShortNickName attribute from the PPD file, if any
throughputintNumber of pages per minute
ttrasterizerchar *The TruType font rasterizer (Type42)
variable_sizesint1 = supports variable sizes
+ +

Options and Groups

+ +

PPD files support multiple options, which are stored in +ppd_option_t and ppd_choice_t structures by +the PPD functions. + +

Each option in turn is associated with a group +stored in the ppd_group_t structure. Groups can be +specified in the PPD file; if an option is not associated with a group +then it is put in a "General" or "Extra" group depending on the option. + +

Groups can also have sub-groups; CUPS currently limits the depth of +sub-groups to 1 level to reduce programming complexity. + +

Conflicts

+ +

PPD files support specification of conflict conditions between +different options. Conflicts are stored in ppd_conflict_t +structures which specify the options that conflict with each other. + +

Page Sizes

+ +

PPD files specify all of the available pages sizes and the physical +margins associated with them. These sizes are stored in +ppd_size_t structures and are available in the +num_sizes and sizes members of the +ppd_file_t structure. You can lookup a particular page size +with the ppdPageWidth(), ppdPageLength(), and +ppdPageSize() functions: + +

    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +ppd_size_t *size;
    +float      width;
    +float      length;
    +
    +...
    +
    +size   = ppdPageSize(ppd, "size");
    +width  = ppdPageWidth(ppd, "size");
    +length = ppdPageLength(ppd, "size");
    +
+ +

The size string is the named page size option. The +width and length are in points; there are 72 points per inch. The +ppd_size_t structure contains the width, length, and +margin information: + +

    +typedef struct    /**** Page Sizes ****/
    +{
    +  int   marked;   /* Page size selected? */
    +  char  name[41]; /* Media size option */
    +  float width,    /* Width of media in points */
    +        length,   /* Length of media in points */
    +        left,     /* Left printable margin in points */
    +        bottom,   /* Bottom printable margin in points */
    +        right,    /* Right printable margin in points */
    +        top;      /* Top printable margin in points */
    +} ppd_size_t;
    +
+ +

Custom Page Sizes

+ +

Besides the standard page sizes listed in a PPD file, some printers +support variable or custom page sizes. If variables_sizes +is non-zero, the custom_min, custom_max, and +custom_margins members of the ppd_file_t +structure define the limits of the variable sizes. + +

To get the resulting media size, use a page size string of +Custom.widthxlength, where width +and length are integer values in points: + +

    +Custom.612x792   [8.5 inches wide, 11 inches long]
    +Custom.1224x792  [17 inches wide, 11 inches long]
    +
+ +

Marking Options

+ +

Before marking any user-defined options, call the ppdMarkDefaults() +function to mark the default options from the PPD file: + +

    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +
    +...
    +
    +ppdMarkDefaults(ppd);
    +
+ +

Then call the ppdMarkOption() function to mark individual +options: + +

    +#include <cups/ppd.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +int        conflicts;
    +
    +...
    +
    +conflicts = ppdMarkOption(ppd, "name", "value");
    +
+ +

The name and value strings choose a +particular option and choice, respectively. The return value is 0 +if there are not conflicts created by the selection. + +

CUPS also provides a convenience function for marking all options +in the cups_option_t structure: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +ppd_file_t    *ppd;
    +int           num_options;
    +cups_option_t *options;
    +int           conflicts;
    +
    +...
    +
    +conflicts = cupsMarkOptions(ppd, num_options, options);
    +
+ +

The cupsMarkOptions() function also handles mapping the +IPP job template attributes to PPD options. The return value is the number +of conflicts present. + +

Checking for Conflicts

+ +

The ppdMarkOption() and cupsMarkOptions() +functions return the number of conflicts with the currently marked options. + +

Call the ppdConflicts() function to get the number of +conflicts after you have marked all of the options: + +

    +#include <cups/cups.h>
    +
    +...
    +
    +ppd_file_t *ppd;
    +int        conflicts;
    +
    +...
    +
    +conflicts = ppdConflicts(ppd);
    +
+ +

The return value is the number of conflicting options, or 0 if there +are no conflicts. + + +

3 - Writing Filters

+ +

This chapter describes how to write a file filter for CUPS. + +

Overview

+ +

File filters are programs that convert from one or more MIME types to +another type. Filters use a common command-line and environment interface +that allows them to be joined as needed to print files to any type of +printer. + +

Security Considerations

+ +

Filters are normally run as a non-priviledged user, so the major +security consideration is resource utilization - filters should not +depend on unlimited amounts of memory and disk space. + +

Users and Groups

+ +

The default CUPS configuration runs filters as user "lp" and group "other". + +

Temporary Files

+ +

Temporary files should be created in the directory specified by the +"TMPDIR" environment variable. The +cupsTempFile() function can be +used to safely choose temporary files in this directory. + +

Sending Messages to the User

+ +

The CUPS scheduler collects messages sent to the standard error file +by the filter. These messages are relayed to the user based upon the +scheduler LogLevel directive. + +

The type of message is determined by an initial prefix sent on each +line: + +

    + +
  • DEBUG: - a debug message + +
  • INFO: - an informational message + +
  • WARNING: - a warning message + +
  • ERROR: - an error message + +
  • PAGE: - a page accounting message + +
+ +

If the line of text does not begin with any of the above prefixes, it +is treated as a debug message. Text following the prefix is copied to the +printer-state-message attribute for the printer, and also +added to the error_log unless it is an informational or page +accounting message. + +

Page Accounting

+ +

Page accounting messages are used to inform the server when one or more +pages are printed. Each line has the form: + +

    +PAGE: page-number copy-count
    +
+ +

The page-number field is the current page number, starting at 1. +The copy-count field specifies the number of copies of that page +that was produced. + +

Page account messages are added to the page_log file and +cause the job-sheets-completed attribute to be updated for +the job. + +

Command-Line Arguments

+ +

Every filter accepts exactly 6 or 7 command-line arguments: + +

    +printer job user title copies options [filename]
    +
    + +
  • printer - The name of the printer queue (normally + this is the name of the program being run) + +
  • job - The numeric job ID for the job being + printed + +
  • user - The string from the + originating-user-name attribute + +
  • title - The string from the + job-name attribute + +
  • copies - The numeric value from the + number-copies attribute + +
  • options - String representations of the + job template attributes, separated by spaces. Boolean attributes + are provided as "name" for true values and "noname" for false + values. All other attributes are provided as "name=value" for + single-valued attributes and "name=value1,value2,...,valueN" for + set attributes + +
  • filename - The request file + +
+ +

The filename argument is only provided to the first filter in the +chain; all filters must be prepared to read the print file from +the standard input if the filename argument is omitted. + +

Copy Generation

+ +

The copies argument specifies the number of copies to produce +of the input file. In general, you should only generate copies if the +filename argument is supplied. The only exception to this are +filters that produce device-independent PostScript output (without any +printer commands from the printer's PPD file), since the PostScript +filter pstops is responsible for copy generation. + +

Environment Variables

+ +

Every filter receives a fixed set of environment variables that can +be used by the filter: + +

    + +
  • CHARSET - The character set used by the client for + this print file + +
  • CONTENT_TYPE - The original document type, such as + "application/postscript" + +
  • CUPS_DATADIR - The location of CUPS data files + +
  • CUPS_SERVERROOT - The location of CUPS configuration + files + +
  • DEVICE_URI - The output device URI + +
  • LANG - The language used by the client for + this print file + +
  • PATH - The execution path exported to the filter + +
  • PPD - The full filename of the printer's PPD file + +
  • PRINTER - The name of the printer queue + +
  • RIP_CACHE - The maximum amount of memory each filter + should use + +
  • SOFTWARE - The name of the CUPS software, typically + "CUPS/1.1" + +
  • TZ - The local timezone + +
  • USER - The name of the current user + +
+ +

Dissecting the HP-GL/2 Filter

+ +

The HP-GL/2 filter (hpgltops) provided with CUPS is a +complex program that converts HP-GL/2 files into device-independent PostScript +output. Since it produces device-independent PostScript output, it does not +need to handle copy generation or writing printer options from the printer's +PPD file. + +

Initializing the Filter

+ +

The first task of any filter is to ensure that the correct number of +command-line arguments are present: + +

    +if (argc < 6 || argc > 7)
    +{
    +  fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr);
    +  return (1);
    +}
    +
+ +

After this you open the print file or read from the standard input +as needed: + +

    +FILE *fp;
    +
    +/*
    + * If we have 7 arguments, print the file named on the command-line.
    + * Otherwise, send stdin instead...
    + */
    +
    +if (argc == 6)
    +  fp = stdin;
    +else
    +{
    + /*
    +  * Try to open the print file...
    +  */
    +
    +  if ((fp = fopen(argv[6], "rb")) == NULL)
    +  {
    +    perror("ERROR: unable to open print file - ");
    +    return (1);
    +  }
    +}
    +
+ +

Once the print file has been opened, options can be processed using +the cupsParseOptions() and +cupsGetOption() functions: + +

    +int           num_options;
    +cups_option_t *options;
    +const char    *val;
    +
    +/*
    + * Process command-line options and write the prolog...
    + */
    +
    +options     = NULL;
    +num_options = cupsParseOptions(argv[5], 0, &options);
    +
    +if ((val = cupsGetOption("blackplot", num_options, options)) != NULL)
    +  shading = 0;
    +
    +if ((val = cupsGetOption("fitplot", num_options, options)) != NULL)
    +  FitPlot = 1;
    +
    +if ((val = cupsGetOption("penwidth", num_options, options)) != NULL)
    +  PenWidth = (float)atoi(val) * 0.001f;
    +
+ +

After the options have been processed, the filter writes PostScript code +to the standard output based on the print file, closes the print file (as +needed), and returns 0 to the scheduler. + +

PostScript Output

+ +

Filters that produce PostScript output must generate output conforming +to the Adobe Document Structuring Conventions, 3.0. In general this means +the beginning of each file must begin with: + +

    +%!PS-Adobe-3.0
    +%%BoundingBox: left bottom right top
    +%%Pages: (atend)
    +%%EndComments
    +
+ +

The left, bottom, right, and top values +are integers in points from the lower-lefthand corner of the page. + +

Pages must be surrounded by: + +

    +%%Page: number number
    +gsave
    +...
    +grestore
    +showpage
    +
+ +

And the end of each file must contain: + +

    +%%Trailer
    +%%Pages: number-pages
    +%%EOF
    +
+ +

These comments allow the PostScript filter to correctly perform page +accounting, copy generation, N-up printing, and so forth. + +

4 - Writing Printer Drivers

+ +

This chapter discusses how to write a printer driver, which is a +special filter program that converts CUPS raster data into the +appropriate commands and data required for a printer. + +

Overview

+ +

Raster printers utilitize PPD files that specify one or more +device-specific filters that handle converting print files for the +printer. The simplest raster printer drivers provide a single filter +that converts CUPS raster data to the printer's native format. + +

CUPS Raster Data

+ +

CUPS raster data (application/vnd.cups-raster) consists of +a stream of raster page descriptions produced by one of the RIP filters, +such as pstoraster or imagetoraster. + +

Each page of data begins with a page dictionary structure called +cups_raster_header_t. This +structure contains the colorspace, bits per color, media size, media type, +hardware resolution, and so forth. + +

After the page dictionary comes the page data which is a full-resolution, +uncompressed bitmap representing the page in the printer's output colorspace. + +

Page Accounting

+ +

Printer drivers must handle all page accounting. This means they must +send "PAGE:" messages to the standard error file for each page (and in many +cases, copy) sent to the printer. + +

Color Management

+ +

Printer drivers can implement their color management via the +cupsColorProfile attributes in the PPD file or internally +in the driver from a device-independent colorspace. In general, color +management performed by the RIP filters is more efficient than that +performed inside printer drivers. + +

For example, the pstoraster filter often only has to +perform a color conversion once each time the color is used for +multiple output pixels, while the raster filter must convert every +pixel on the page. + +

Device and Bitmap Variables

+ +

Besides the standard PostScript page device dictionary variables defined +in the Adobe PostScript Level 3 reference manual, the CUPS filters support +additional variables that are passed in the page device dictionary header for +the page and in some cases control the type of raster data that is generated: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableTypeDescription
cupsWidthread-only integerWidth of bitmap in pixels
cupsHeightread-only integer Height of bitmap in pixels
cupsMediaTyperead-write integerDevice-specific media type code
cupsBitsPerColorread-write integerNumber of bits per color; 1, 2, 4, and 8 are currently + supported
cupsBitsPerPixelread-only integer Number of bits per pixel; 1 to 32
cupsBytesPerLineread-only integerNumber of bytes per line of raster graphics
cupsColorOrderread-write enumThe order of color values in the bitmap: +
    +
  • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK +
  • CUPS_ORDER_BANDED - CCC MMM YYY KKK +
  • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ... +
+
cupsColorSpaceread-write enumThe colorspace of the bitmap: +
    +
  • CUPS_CSPACE_W - White (luminance) +
  • CUPS_CSPACE_RGB - Red, green, blue +
  • CUPS_CSPACE_RGBA - Red, green, blue, alpha +
  • CUPS_CSPACE_K - Black +
  • CUPS_CSPACE_CMY - Cyan, magenta, yellow +
  • CUPS_CSPACE_YMC - Yellow, magenta, cyan +
  • CUPS_CSPACE_CMYK - Cyan, magenta, yellow, black +
  • CUPS_CSPACE_YMCK - Yellow, magenta, cyan, black +
  • CUPS_CSPACE_KCMY - Black, cyan, magenta, yellow +
  • CUPS_CSPACE_KCMYcm - Black, cyan, magenta, yellow, + light cyan, light magenta +
  • CUPS_CSPACE_GMCK - Metallic yellow (gold), metallic magenta, + metallic cyan, black +
  • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic magenta, + metallic cyan, metallic grey (silver) +
  • CUPS_CSPACE_WHITE - White pigment (black as white pigment) +
  • CUPS_CSPACE_GOLD - Gold foil (black as gold foil) +
  • CUPS_CSPACE_SILVER - Silver foil (black as silver foil) +
+
cupsCompressionread-write integerDevice-specific compression type code
cupsRowCountread-write integerDevice-specific row count value
cupsRowFeedread-write integerDevice-specific row feed value
cupsRowStepread-write integerDevice-specific row step value
+ +

Bitmaps with a colorspace of CUPS_CSPACE_KCMYcm and more than 1 bit per +color are transmitted to the raster driver in KCMY colorspace; the driver +is responsible for producing the correct separation of normal and light +cyan and magenta inks. + +

Dissecting the HP-PCL Driver

+ +

The HP-PCL driver provided with CUPS (rastertohp) converts +bitmap data from the raster filters into HP-PCL commands for most +PCL-compatible printers. The actual format of the raster data is controlled +by the PPD file being used - deskjet.ppd or laserjet.ppd. + +

PPD Files

+ +

PPD files play an important part of all raster printer drivers. Options +defined in the PPD file contain PostScript commands that control the raster +data that is sent to the printer driver. + +

A typical CUPS printer driver will include ColorModel, +InputSlot, PageSize, PageRegion, +and Resolution options. Each option is shown using the +standard PPD format: + +

    +*OpenUI *PageSize/Media Size: PickOne
    +*OrderDependency: 10 AnySetup *PageSize
    +*DefaultPageSize: Letter
    +*PageSize Letter/US Letter: "<<
    +/PageSize [612 792]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*PageSize Legal/US Legal: "<<
    +/PageSize [612 1008]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*PageSize A4/A4: "<<
    +/PageSize [595 842]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +*CloseUI: *PageSize
    +
+ +

The OpenUI keyword specifies the new option. The first +name is the option with an asterisk (*) in front of it. The first name is +usually followed by a slash (/) and a human-readable version of the +option name. + +

Every option must have a default value, specified using the +DefaultOption keyword. + +

Each option begins with the option name followed by the computer and +human-readable values. The PostScript commands follow these inside double +quotes. PostScript commands can be provided on a single line: + +

    +*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>> setpagedevice"
    +
+ +

or broken down on separate lines using the End keyword to +terminate them: + +

    +*PageSize A4/A4: "<<
    +/PageSize [595 842]
    +/ImagingBBox null
    +>> setpagedevice"
    +*End
    +
+ +

The choice of the two formats is usually esthetic. However, each line in +a PPD file must not exceed 255 characters, so if your PostScript commands are +long you may need to break them up on separate lines. + +

Reading Raster Data

+ +

As with any filter, your printer driver should handle raster data from +a filename specified on the command-line or from the standard input. The +cupsRasterOpen() function opens +a raster stream for printing: + +

    +int           fd;   /* File descriptor */
    +cups_raster_t *ras; /* Raster stream for printing */
    +
    +
    +/*
    + * Check for valid arguments...
    + */
    +
    +if (argc < 6 || argc > 7)
    +{
    + /*
    +  * We don't have the correct number of arguments; write an error message
    +  * and return.
    +  */
    +
    +  fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr);
    +  return (1);
    +}
    +
    +/*
    + * Open the page stream...
    + */
    +
    +if (argc == 7)
    +{
    +  if ((fd = open(argv[6], O_RDONLY)) == -1)
    +  {
    +    perror("ERROR: Unable to open raster file - ");
    +    sleep(1);
    +    return (1);
    +  }
    +}
    +else
    +  fd = 0;
    +
    +ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
    +
+ +

Once you have opened the raster stream you just need to read each +page and print it: + +

    +cups_raster_header_t header;
    +int                  y;
    +unsigned char        data[8192];
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ... initialize the printer ...
    +  for (y = header.cupsHeight; y > 0; y ++)
    +  {
    +    cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
    +    ... send raster line to printer ...
    +  }
    +}
    +
+ +

After you have processed all pages, close the raster stream and +return: + +

    +cupsRasterClose(ras);
    +
    +return (0);
    +
+ +

5 - Writing Backends

+ +

This chapter describes how to write a backend for CUPS. Backends +communicate directly with printers and allow printer drivers and +filters to send data using any type of connection transparently. + +

Overview

+ +

Backends are special filters that communicate with printers directly. +They are treated slightly differently than filters, however, and have some +unique requirements. + +

Security Considerations

+ +

Backends are run as the root user, so special care must be taken to +avoid potential security violations. In particular, remember that a backend +will be able to manipulate disk files, devices, and other resources that +potentially could damage a system or printer. + +

Command-Line Arguments

+ +

Besides the standard filter arguments, backends are also run with no +arguments to get a list of available devices. This discovery process is +described later in this chapter. + +

Copy Generation

+ +

Like filters, backends should send multiple copies of the print file only +if a filename is supplied on the command-line. Otherwise the backend should +assume that the upstream filter has already added the necessary commands or +data to produce the multiple copies. + +

Page Accounting

+ +

Backend filters generally do not do page accounting, however they should +at a minimum produce a single page message for each copy that is produced +when a filename is present on the command-line. This is because the user +selected "raw" printing and no other accounting information is possible. + +

Exclusive Access

+ +

Backends that talk to local character or block devices should open the +device file in exclusive mode (O_EXCL) to cooperate with other +printers defined for the same device. + +

Retries

+ +

All backends must retry connections to the device. This +includes backends that talk to local character or block devices, as the +user may define more than one printer queue pointing at the same +physical device. + +

To prevent excess CPU utilitization, the backend should go to sleep +for an amount of time between retries; the CUPS-supplied backends retry +once every 30 seconds. + +

Dissecting the Serial Port Backend

+ +

The serial port backend provides support for serial printers. Since +it does everything a good backend needs to do, it provides an excellent +example of what to do. + +

Supporting Device Discovery

+ +

As previously noted, backends are special filter programs that talk +to printer devices. Another task a backend must perform is to list the +available devices it supports. The backend lists the available devices +when no additioanl arguments are supplied on the command-line (i.e. +just the command name...) + +

The serial backend lists devices by looking at serial port files in the +/dev directory, by consulting a hardware inventory (IRIX), and +in some cases by trying to open the ports to see if they actually exist. + +

Once it finds a serial port it writes a single line for each port to +the standard error file. Each line looks like this: + +

    +serial serial:/dev/ttyS0?baud=115200 "Unknown" "Serial Port 1"
    +
+ +

The first word "serial" is the device class; this identifies the +class of device which can be used to categorize it in user interfaces. CUPS +currently recognizes the following classes: + +

    + +
  • "file" - a disk file. + +
  • "direct" - a parallel or fixed-rate serial data port, + currently used for Centronics, IEEE-1284, and USB printer + ports. + +
  • "serial" - a variable-rate serial port. + +
  • "network" - a network connection, typically via AppSocket, + HTTP, IPP, LPD, or SMB/CIFS protocols. + +
+ +

After the device class is the device URI, in this case +"serial:/dev/ttyS0?baud=115200". This is the URI that should be used by +the user to select this port. For serial ports, the "baud=115200" +specifies the maximum baud rate supported by the port - the actual +value will vary based on the speed the user selects for the printer. + +

The last two strings are the model and description for the port. The +"Unknown" string means that the printer model is unknown - some devices +are able to provide a make and model such as "HP DeskJet" that allows +users and software to choose an appropriate printer driver more easily. +Both the model and description must be enclosed inside double quotes. + +

Opening the Serial Port

+ +

As noted previously, all backends should open device files in exclusive +mode, and retry as needed until the port is available. The serial port does +this using a do-while loop: + +

    +do
    +{
    +  if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
    +  {
    +    if (errno == EBUSY)
    +    {
    +      fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
    +      sleep(30);
    +    }
    +    else
    +    {
    +      perror("ERROR: Unable to open serial port device file");
    +      return (1);
    +    }
    +  }
    +}
    +while (fd < 0);
    +
+ +

If the port is busy or in use by another process, the backend will +go to sleep for 30 seconds and try again. If another error is detected +a message is sent to the user and the backend aborts the print job +until the problem can be corrected. + +

Writing Data to the Port

+ +

Network and character devices pose an interesting problem when writing +data to the port - they may not be able to write all of the bytes in your +buffer before returning. To work around this problem you must loop until +all bytes have been written: + +

    +while (nbytes > 0)
    +{
    +  if ((wbytes = write(fd, bufptr, nbytes)) < 0)
    +    if (errno == ENOTTY)
    +      wbytes = write(fd, bufptr, nbytes);
    +
    +  if (wbytes < 0)
    +  {
    +    perror("ERROR: Unable to send print file to printer");
    +    break;
    +  }
    +
    +  nbytes -= wbytes;
    +  bufptr += wbytes;
    +}
    +
+ +

The check for the ENOTTY error is needed on some platforms +to clear an error from a previous ioctl() call. + +

Finishing Up

+ +

Once you have sent the print file, return 0 if the file printed +successfully or 1 if it did not. This will allow the scheduler to stop +the print job if there is a device error, preserving the print job for +later printing once the problem has been corrected. + +

A - Software License Agreement

+ + + + +

B - Constants

+ +

This appendix lists all of the constants that are defined by the CUPS +API. + +

CUPS Constants

+ +

Version Number

+ +

The CUPS_VERSION constant is a floating-point number +representing the API version number. The current version number is +1.0100 which represents CUPS version 1.1.0. + +

Printer Capabilities

+ +

The CUPS_PRINTER constants represent capability bits for +printers and classes: + +

    + +
  • CUPS_PRINTER_LOCAL - Is a local printer or class. + +
  • CUPS_PRINTER_REMOTE - Is a remote printer or class. + +
  • CUPS_PRINTER_CLASS - Is a class. + +
  • CUPS_PRINTER_BW - Printer prints in black and white. + +
  • CUPS_PRINTER_COLOR - Printer prints in color. + +
  • CUPS_PRINTER_DUPLEX - Printer can print double-sided. + +
  • CUPS_PRINTER_STAPLE - Printer can staple output. + +
  • CUPS_PRINTER_COPIES - Printer can produce multiple + copies on its own. + +
  • CUPS_PRINTER_COLLATE - Printer can collate copies. + +
  • CUPS_PRINTER_PUNCH - Printer can punch holes in output. + +
  • CUPS_PRINTER_COVER - Printer can put covers on output. + +
  • CUPS_PRINTER_BIND - Printer can bind output. + +
  • CUPS_PRINTER_SORT - Printer can sort output. + +
  • CUPS_PRINTER_SMALL - Printer can print on media up + to 9x14 inches. + +
  • CUPS_PRINTER_MEDIUM - Printer can print on media + from 9x14 to 18x24 inches. + +
  • CUPS_PRINTER_LARGE - Printer can print on media + larger than 18x24 inches. + +
  • CUPS_PRINTER_VARIABLE - Printer can print on + variable or custom media sizes. + +
  • CUPS_PRINTER_IMPLICIT - Is an implicit class. + +
  • CUPS_PRINTER_OPTIONS - All of the printer capability + and option bits. + +
+ +

Encodings

+ +

CUPS defines the following character set encoding constants: + +

    + +
  • CUPS_US_ASCII - US ASCII character set. + +
  • CUPS_UTF_8 - UTF-8 encoding of Unicode. + +
  • CUPS_ISO8859_1 - ISO-8859-1 character set. + +
  • CUPS_ISO8859_2 - ISO-8859-2 character set. + +
  • CUPS_ISO8859_3 - ISO-8859-3 character set. + +
  • CUPS_ISO8859_4 - ISO-8859-4 character set. + +
  • CUPS_ISO8859_5 - ISO-8859-5 character set. + +
  • CUPS_ISO8859_6 - ISO-8859-6 character set. + +
  • CUPS_ISO8859_7 - ISO-8859-7 character set. + +
  • CUPS_ISO8859_8 - ISO-8859-8 character set. + +
  • CUPS_ISO8859_9 - ISO-8859-9 character set. + +
  • CUPS_ISO8859_10 - ISO-8859-10 character set. + +
  • CUPS_ISO8859_13 - ISO-8859-13 character set. + +
  • CUPS_ISO8859_14 - ISO-8859-14 character set. + +
  • CUPS_ISO8859_15 - ISO-8859-15 character set. + +
  • CUPS_WINDOWS_874 - Windows code page 874. + +
  • CUPS_WINDOWS_1250 - Windows code page 1250. + +
  • CUPS_WINDOWS_1251 - Windows code page 1251. + +
  • CUPS_WINDOWS_1252 - Windows code page 1252. + +
  • CUPS_WINDOWS_1253 - Windows code page 1253. + +
  • CUPS_WINDOWS_1254 - Windows code page 1254. + +
  • CUPS_WINDOWS_1255 - Windows code page 1255. + +
  • CUPS_WINDOWS_1256 - Windows code page 1256. + +
  • CUPS_WINDOWS_1257 - Windows code page 1257. + +
  • CUPS_WINDOWS_1258 - Windows code page 1258. + +
+ +

HTTP Constants

+ +

Limits

+ +

The following constants define the limits for strings: + +

    + +
  • HTTP_MAX_BUFFER - Size of socket buffer. + +
  • HTTP_MAX_HOST - Maximum length of hostname. + +
  • HTTP_MAX_URI - Maximum length of URI. + +
  • HTTP_MAX_VALUE - Maximum length of field values. + +
+ +

Status Codes

+ +

The following status codes can be returned by httpUpdate(): + +

    + +
  • HTTP_ERROR - A network error occurred + +
  • HTTP_CONTINUE - Continue response from HTTP proxy + +
  • HTTP_OK - OPTIONS/GET/HEAD/POST/TRACE command was successful + +
  • HTTP_CREATED - PUT command was successful + +
  • HTTP_ACCEPTED - DELETE command was successful + +
  • HTTP_NOT_AUTHORITATIVE - Information isn't authoritative + +
  • HTTP_NO_CONTENT - Successful command + +
  • HTTP_RESET_CONTENT - Content was reset/recreated + +
  • HTTP_PARTIAL_CONTENT - Only a partial file was recieved/sent + +
  • HTTP_MULTIPLE_CHOICES - Multiple files match request + +
  • HTTP_MOVED_PERMANENTLY - Document has moved permanently + +
  • HTTP_MOVED_TEMPORARILY - Document has moved temporarily + +
  • HTTP_SEE_OTHER - See this other link... + +
  • HTTP_NOT_MODIFIED - File not modified + +
  • HTTP_USE_PROXY - Must use a proxy to access this URI + +
  • HTTP_BAD_REQUEST - Bad request + +
  • HTTP_UNAUTHORIZED - Unauthorized to access host + +
  • HTTP_PAYMENT_REQUIRED - Payment required + +
  • HTTP_FORBIDDEN - Forbidden to access this URI + +
  • HTTP_NOT_FOUND - URI was not found + +
  • HTTP_METHOD_NOT_ALLOWED - Method is not allowed + +
  • HTTP_NOT_ACCEPTABLE - Not Acceptable + +
  • HTTP_PROXY_AUTHENTICATION - Proxy Authentication is Required + +
  • HTTP_REQUEST_TIMEOUT - Request timed out + +
  • HTTP_CONFLICT - Request is self-conflicting + +
  • HTTP_GONE - Server has gone away + +
  • HTTP_LENGTH_REQUIRED - A content length or encoding is required + +
  • HTTP_PRECONDITION - Precondition failed + +
  • HTTP_REQUEST_TOO_LARGE - Request entity too large + +
  • HTTP_URI_TOO_LONG - URI too long + +
  • HTTP_UNSUPPORTED_MEDIATYPE - The requested media type is unsupported + +
  • HTTP_SERVER_ERROR - Internal server error + +
  • HTTP_NOT_IMPLEMENTED - Feature not implemented + +
  • HTTP_BAD_GATEWAY - Bad gateway + +
  • HTTP_SERVICE_UNAVAILABLE - Service is unavailable + +
  • HTTP_GATEWAY_TIMEOUT - Gateway connection timed out + +
  • HTTP_NOT_SUPPORTED - HTTP version not supported + +
+ +

Fields

+ +

The following fields are indices for each of the standard HTTP fields in +HTTP 1/1: + +

    + +
  • HTTP_FIELD_ACCEPT_LANGUAGE - Accept-Language + +
  • HTTP_FIELD_ACCEPT_RANGES - Accept-Ranges + +
  • HTTP_FIELD_AUTHORIZATION - Authorization + +
  • HTTP_FIELD_CONNECTION - Connection + +
  • HTTP_FIELD_CONTENT_ENCODING - Content-Encoding + +
  • HTTP_FIELD_CONTENT_LANGUAGE - Content-Language + +
  • HTTP_FIELD_CONTENT_LENGTH - Content-Length + +
  • HTTP_FIELD_CONTENT_LOCATION - Content-Location + +
  • HTTP_FIELD_CONTENT_MD5 - Content-MD5 + +
  • HTTP_FIELD_CONTENT_RANGE - Content-Range + +
  • HTTP_FIELD_CONTENT_TYPE - Content-Type + +
  • HTTP_FIELD_CONTENT_VERSION - Content-Version + +
  • HTTP_FIELD_DATE - Date + +
  • HTTP_FIELD_HOST - Host + +
  • HTTP_FIELD_IF_MODIFIED_SINCE - If-Modified-Since + +
  • HTTP_FIELD_IF_UNMODIFIED_SINCE - If-Unmodified-Since + +
  • HTTP_FIELD_KEEP_ALIVE - Keep-Alive + +
  • HTTP_FIELD_LAST_MODIFIED - Last-Modified + +
  • HTTP_FIELD_LINK - Link + +
  • HTTP_FIELD_LOCATION - Location + +
  • HTTP_FIELD_RANGE - Range + +
  • HTTP_FIELD_REFERER - Referer + +
  • HTTP_FIELD_RETRY_AFTER - Retry-After + +
  • HTTP_FIELD_TRANSFER_ENCODING - Transfer-Encoding + +
  • HTTP_FIELD_UPGRADE - Upgrade + +
  • HTTP_FIELD_USER_AGENT - User-Agent + +
  • HTTP_FIELD_WWW_AUTHENTICATE - WWW-Authenticate + + +
+ +

IPP Constants

+ +

Limits

+ +

The following constants define array limits for IPP data: + +

    + +
  • IPP_MAX_NAME - Maximum length of an attribute name + +
  • IPP_MAX_VALUES - Maximum number of set-of values + that can be read in a request. + +
+ +

Tags

+ +
    + +
  • IPP_TAG_ZERO - Wildcard tag value for searches; also + used to separate groups of attributes + +
  • IPP_TAG_OPERATION - Tag for values of type operation + +
  • IPP_TAG_JOB - Tag for values of type job + +
  • IPP_TAG_END - Tag for values of type end + +
  • IPP_TAG_PRINTER - Tag for values of type printer + +
  • IPP_TAG_UNSUPPORTED_GROUP - Tag for values of type unsupported_group + +
  • IPP_TAG_UNSUPPORTED_VALUE - Tag for values of type unsupported_value + +
  • IPP_TAG_DEFAULT - Tag for values of type default + +
  • IPP_TAG_UNKNOWN - Tag for values of type unknown + +
  • IPP_TAG_NOVALUE - Tag for values of type novalue + +
  • IPP_TAG_NOTSETTABLE - Tag for values of type notsettable + +
  • IPP_TAG_DELETEATTR - Tag for values of type deleteattr + +
  • IPP_TAG_ANYVALUE - Tag for values of type anyvalue + +
  • IPP_TAG_INTEGER - Tag for values of type integer + +
  • IPP_TAG_BOOLEAN - Tag for values of type boolean + +
  • IPP_TAG_ENUM - Tag for values of type enum + +
  • IPP_TAG_STRING - Tag for values of type string + +
  • IPP_TAG_DATE - Tag for values of type date + +
  • IPP_TAG_RESOLUTION - Tag for values of type resolution + +
  • IPP_TAG_RANGE - Tag for values of type range + +
  • IPP_TAG_COLLECTION - Tag for values of type collection + +
  • IPP_TAG_TEXTLANG - Tag for values of type textlang + +
  • IPP_TAG_NAMELANG - Tag for values of type namelang + +
  • IPP_TAG_TEXT - Tag for values of type text + +
  • IPP_TAG_NAME - Tag for values of type name + +
  • IPP_TAG_KEYWORD - Tag for values of type keyword + +
  • IPP_TAG_URI - Tag for values of type uri + +
  • IPP_TAG_URISCHEME - Tag for values of type urischeme + +
  • IPP_TAG_CHARSET - Tag for values of type charset + +
  • IPP_TAG_LANGUAGE - Tag for values of type language + +
  • IPP_TAG_MIMETYPE - Tag for values of type mimetype + +
+ +

Resolution Units

+ +

The IPP_RES_PER_INCH and IPP_RES_PER_CM constants +specify dots per inch and dots per centimeter, respectively. + +

Finishings

+ +

The finishing values specify special finishing operations to be +performed on the job. + +

    + +
  • IPP_FINISH_NONE - Do no finishing + +
  • IPP_FINISH_STAPLE - Staple the job + +
  • IPP_FINISH_PUNCH - Punch the job + +
  • IPP_FINISH_COVER - Cover the job + +
  • IPP_FINISH_BIND - Bind the job + +
+ +

Orientations

+ +

The orientation values specify the orientation of the job. + +

    + +
  • IPP_PORTRAIT - No rotation + +
  • IPP_LANDSCAPE - 90 degrees counter-clockwise + +
  • IPP_REVERSE_LANDSCAPE - 90 degrees clockwise + +
  • IPP_REVERSE_PORTRAIT - 180 degrees + +
+ +

Qualities

+ +

The quality values specify the desired quality of the print. +

    + +
  • IPP_QUALITY_DRAFT - Draft quality + +
  • IPP_QUALITY_NORMAL - Normal quality + +
  • IPP_QUALITY_HIGH - High quality + +
+ +

Job States

+ +

The job state values are used to represent the current job state. + +

    + +
  • IPP_JOB_PENDING - Job is pending + +
  • IPP_JOB_HELD - Job is held + +
  • IPP_JOB_PROCESSING - Job is processing + +
  • IPP_JOB_STOPPED - Job is stopped + +
  • IPP_JOB_CANCELLED - Job is cancelled + +
  • IPP_JOB_ABORTED - Job is aborted + +
  • IPP_JOB_COMPLETED - Job is completed + +
+ +

Printer States

+ +

The printer state values are used to represent the current printer +state. + +

    + +
  • IPP_PRINTER_IDLE - Printer is idle + +
  • IPP_PRINTER_PROCESSING - Printer is processing + +
  • IPP_PRINTER_STOPPED - Printer is stopped + +
+ +

Operations

+ +

The operation values represent the available IPP operations. + +

    + +
  • IPP_PRINT_JOB - Print a file + +
  • IPP_PRINT_URI - Print a URI + +
  • IPP_VALIDATE_JOB - Validate job attributes + +
  • IPP_CREATE_JOB - Create a new job + +
  • IPP_SEND_DOCUMENT - Send a document to a job + +
  • IPP_SEND_URI - Send a URI to a job + +
  • IPP_CANCEL_JOB - Cancel a job + +
  • IPP_GET_JOB_ATTRIBUTES - Get job attributes + +
  • IPP_GET_JOBS - Get a list of all jobs + +
  • IPP_GET_PRINTER_ATTRIBUTES - Get printer attributes + +
  • IPP_HOLD_JOB - Hold a pending job + +
  • IPP_RELEASE_JOB - Release a held job + +
  • IPP_RESTART_JOB - Restart a completed job + +
  • IPP_PAUSE_PRINTER - Pause a printer + +
  • IPP_RESUME_PRINTER - Restart a paused printer + +
  • IPP_PURGE_JOBS - Purge jobs from the queue + +
  • IPP_SET_PRINTER_ATTRIBUTES - Set printer attributes + +
  • IPP_SET_JOB_ATTRIBUTES - Set job attributes + +
  • IPP_GET_PRINTER_SUPPORTED_VALUES - Get printer supported values + +
  • CUPS_GET_DEFAULT - Get the default destination + +
  • CUPS_GET_PRINTERS - Get a list of all printers + +
  • CUPS_ADD_PRINTER - Add or modify a printer + +
  • CUPS_DELETE_PRINTER - Delete a printer + +
  • CUPS_GET_CLASSES - Get a list of all classes + +
  • CUPS_ADD_CLASS - Add or modify a class + +
  • CUPS_DELETE_CLASS - Delete a class + +
  • CUPS_ACCEPT_JOBS - Accept jobs on a printer or class + +
  • CUPS_REJECT_JOBS - Reject jobs on a printer or class + +
  • CUPS_SET_DEFAULT - Set the default destination + +
  • CUPS_GET_DEVICES - Get a list of all devices + +
  • CUPS_GET_PPDS - Get a list of all PPDs + +
  • CUPS_MOVE_JOB - Move a job to a new destination + +
+ +

Status Codes

+ +

Status codes are returned by all IPP requests. + +

    + +
  • IPP_OK - Request completed with no errors + +
  • IPP_OK_SUBST - Request completed but some attribute + values were substituted + +
  • IPP_OK_CONFLICT - Request completed but some attributes + conflicted + +
  • IPP_BAD_REQUEST - The request was bad + +
  • IPP_FORBIDDEN - You don't have access to the resource + +
  • IPP_NOT_AUTHENTICATED - You are not authenticated for + the resource + +
  • IPP_NOT_AUTHORIZED - You not authorized to access + the resource + +
  • IPP_NOT_POSSIBLE - The requested operation cannot be + completed + +
  • IPP_TIMEOUT - A timeout occurred + +
  • IPP_NOT_FOUND - The resource was not found + +
  • IPP_GONE - The resource has gone away + +
  • IPP_REQUEST_ENTITY - The request was too large + +
  • IPP_REQUEST_VALUE - The request contained a value + that was unknown to the server + +
  • IPP_DOCUMENT_FORMAT - The document format is not + supported by the server + +
  • IPP_ATTRIBUTES - Required attributes are missing + +
  • IPP_URI_SCHEME - The URI scheme is not supported + +
  • IPP_CHARSET - The charset is not supported + +
  • IPP_CONFLICT - One or more attributes conflict + +
  • IPP_COMPRESSION_NOT_SUPPORTED - The specified + compression is not supported + +
  • IPP_COMPRESSION_ERROR - The compressed data + contained an error + +
  • IPP_DOCUMENT_FORMAT_ERROR - The document data + contained an error in it + +
  • IPP_DOCUMENT_ACCESS_ERROR - The remote document + could not be accessed + +
  • IPP_INTERNAL_ERROR - The server encountered an + internal error + +
  • IPP_OPERATION_NOT_SUPPORTED - The requested operation + is not supported + +
  • IPP_SERVICE_UNAVAILABLE - The requested service + is unavailable + +
  • IPP_VERSION_NOT_SUPPORTED - The IPP request + version is not supported + +
  • IPP_DEVICE_ERROR - The output device encountered + an error + +
  • IPP_TEMPORARY_ERROR - A temporary error occurred + +
  • IPP_NOT_ACCEPTING - The destination is not accepting + jobs + +
  • IPP_PRINTER_BUSY - The destination is busy + +
  • IPP_ERROR_JOB_CANCELLED - The requested job has been + cancelled + +
  • IPP_MULTIPLE_JOBS_NOT_SUPPORTED - The server + does not support multiple jobs + +
+ +

PPD Constants

+ +

PPD Format Version

+ +

The PPD_VERSION constant defines a floating point number +representing the newest format version that is supported by CUPS, currently +4.3. + +

PPD User-Interface Types

+ +

Each printer option has a type associated with it: + +

    + +
  • PPD_UI_BOOLEAN - The user can turn this option on or off + +
  • PPD_UI_PICKONE - The user can choose one option value + to use. + +
  • PPD_UI_PICKMANY - The user can choose zero or more + option values. + +
+ +

PPD Sections

+ +

Some options must be output before others, or in different sections of +the output document. The ppd_section_t enumeration defines +which section the option must be output in: + +

    + +
  • PPD_ORDER_ANY - The option can be output in any of + the document, page, or prolog sections of the document + +
  • PPD_ORDER_DOCUMENT - The option must be output in + the DocumentSetup section of the document + +
  • PPD_ORDER_EXIT - The option must be output before + the document + +
  • PPD_ORDER_JCL - The option must be output in the + job control section of the document + +
  • PPD_ORDER_PAGE - The option must be output in the + PageSetup section of the document + +
  • PPD_ORDER_PROLOG - The option must be output in the + Prolog section of the document + +
+ +

PPD Colorspaces

+ +

Each printer has a default colorspace: + +

    + +
  • PPD_CS_CMYK - The printer uses CMYK colors by default + +
  • PPD_CS_CMY - The printer uses CMY colors by default + +
  • PPD_CS_GRAY - The printer uses grayscale by default + +
  • PPD_CS_RGB - The printer uses RGB colors by default + +
  • PPD_CS_RGBK - The printer uses RGBK colors by default + +
  • PPD_CS_N - The printer uses a DeviceN colorspace + by default + +
+ +

Raster Constants

+ +

Raster Sync Words

+ +

The CUPS_RASTER_SYNC and CUPS_RASTER_REVSYNC +constants define the standard sync words at the beginning of each CUPS +raster file. + +

Raster Stream Modes

+ +

The CUPS_RASTER_READ and CUPS_RASTER_WRITE +constants are used with the +cupsRasterOpen() function to +specify a stream for reading or writing. + +

Raster Boolean Constants

+ +

The CUPS_FALSE and CUPS_TRUE constants +represent boolean values in the page header. + +

Raster Jog Values

+ +

The cups_jog_t enumeration defines constants for the +Jog page device dictionary variable: + +

    + +
  • CUPS_JOG_NONE - Do no jogging + +
  • CUPS_JOG_FILE - Jog pages after each file + +
  • CUPS_JOG_JOB - Jog pages after each job + +
  • CUPS_JOG_SET - Jog pages after each set of jobs + +
+ +

Raster Orientation Values

+ +

The cups_orient_t enumeration defines constants for the +Orientation page device dictionary variable: + +

    + +
  • CUPS_ORIENT_0 - Portrait orientation + +
  • CUPS_ORIENT_90 - Landscape orientation + +
  • CUPS_ORIENT_180 - Reverse-portrait orientation + +
  • CUPS_ORIENT_270 - Reverse-landscape orientation + +
+ +

Raster CutMedia Values

+ +

The cups_cut_t enumeration defines constants for the +CutMedia page device dictionary variable: + +

    + +
  • CUPS_CUT_NONE - Do no jogging + +
  • CUPS_CUT_FILE - Cut pages after each file + +
  • CUPS_CUT_JOB - Cut pages after each job + +
  • CUPS_CUT_SET - Cut pages after each set of jobs + +
  • CUPS_CUT_PAGE - Cut each page + +
+ +

Raster AdvanceMedia Values

+ +

The cups_advance_t enumeration defines constants for the +AdvanceMedia page device dictionary variable: + +

    + +
  • CUPS_ADVANCE_NONE - Do no jogging + +
  • CUPS_ADVANCE_FILE - Advance media after each file + +
  • CUPS_ADVANCE_JOB - Advance media after each job + +
  • CUPS_ADVANCE_SET - Advance media after each set of jobs + +
  • CUPS_ADVANCE_PAGE - Advance media for each page + +
+ +

Raster LeadingEdge Values

+ +

The cups_edge_t enumeration defines constants for the +LeadingEdge page device dictionary variable: + +

    + +
  • CUPS_EDGE_TOP - The top of the media is the leading + edge + +
  • CUPS_EDGE_RIGHT - The right of the media is the leading + edge + +
  • CUPS_EDGE_BOTTOM - The bottom of the media is the + leading edge + +
  • CUPS_EDGE_LEFT - The left of the media is the leading + edge + +
+ +

Raster Color Order Values

+ +

The cups_order_t enumeration defines the possible color +value orderings: + +

    + +
  • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK + +
  • CUPS_ORDER_BANDED - CCC MMM YYY KKK + +
  • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ... + +
+ +

Raster Colorspace Values

+ +

The cups_cspace_t enumeration defines the possible colorspaces: + +

    + +
  • CUPS_CSPACE_W - White (luminance) + +
  • CUPS_CSPACE_RGB - Red, green, blue + +
  • CUPS_CSPACE_RGBA - Red, green, blue, alpha + +
  • CUPS_CSPACE_K - Black + +
  • CUPS_CSPACE_CMY - Cyan, magenta, yellow + +
  • CUPS_CSPACE_YMC - Yellow, magenta, cyan + +
  • CUPS_CSPACE_CMYK - Cyan, magenta, yellow, black + +
  • CUPS_CSPACE_YMCK - Yellow, magenta, cyan, black + +
  • CUPS_CSPACE_KCMY - Black, cyan, magenta, yellow + +
  • CUPS_CSPACE_KCMYcm - Black, cyan, magenta, yellow, + light cyan, light magenta + +
  • CUPS_CSPACE_GMCK - Metallic yellow (gold), metallic magenta, + metallic cyan, black + +
  • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic magenta, + metallic cyan, metallic grey (silver) + +
  • CUPS_CSPACE_WHITE - White pigment (black as white pigment) + +
  • CUPS_CSPACE_GOLD - Gold foil (black as gold foil) + +
  • CUPS_CSPACE_SILVER - Silver foil (black as silver foil) + +
+ +

C - Structures

+ +

This appendix describes all of the structures that are defined by the CUPS +API. + +

Raster Structures

+ +

Raster Page Header

+ +

The raster page header consists of the PostScript page device dictionary +for the page: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
MediaClasschar[64]The media class name
MediaColorchar[64]The media color name
MediaTypechar[64]The media type name
OutputTypechar[64]The output type name
AdvanceDistanceunsignedThe distance to advance the media in points
AdvanceMediacups_adv_tWhen to advance the media
Collatecups_bool_tWhether or not to produce collated copies
CutMediacups_cut_tWhen to cut the media
Duplexcups_bool_tWhether or not to print on both sides of the paper
HWResolutionunsigned[2]The resolution of the page image in pixels per inch; the + HWResolution[0] represents the horizontal resolution and + HWResolution[1] represents the vertical resolution
ImagingBoundingBoxunsigned[4]The bounding box for the page in points; the elements + represent the left, bottom, right, and top coordinates of the + imaged area (if 0 then the whole page is imaged)
InsertSheetcups_bool_tWhether or not to insert a sheet before this page
Jogcups_jog_tWhen to jog copies of the page
LeadingEdgecups_edge_tThe leading edge of the page
Marginsunsigned[2]The lower-lefthand margin of the page in points
ManualFeedcups_bool_tWhether or not to manually feed the page
MediaPositionunsignedThe input slot number to use
MediaWeightunsignedThe weight of the output media in grams/m2
MirrorPrintcups_bool_tWhether or not to mirror the print
NegativePrintcups_bool_tWhether or not to invert the print
NumCopiesunsignedThe number of copies to produce
Orientationcups_orient_tThe orientation of the page image
OutputFaceUpcups_bool_tWhether or not to output the page face up
PageSizeunsigned[2]The width and height of the page in points
Separationscups_bool_tWhether or not to output separations
TraySwitchcups_bool_tWhether or not to automatically switch trays for the requested + media size/type
Tumblecups_bool_tWhether or not to rotate the back side of the page
cupsWidthunsignedThe width of the page image in pixels
cupsHeightunsignedThe height of the page image in pixels
cupsMediaTypeunsignedThe device-specific media type code
cupsBitsPerColorunsignedThe number of bits per color
cupsBitsPerPixelunsignedThe number of bits per pixel
cupsBytesPerLineunsignedThe number of bytes per line of image data
cupsColorOrdercups_order_tThe order of color values
cupsColorSpacecups_cspace_tThe type of color values
cupsCompressionunsignedThe device-specific compression code
cupsRowCountunsignedThe device-specific row count
cupsRowFeedunsignedThe device-specific row feed
cupsRowStepunsignedThe device-specific row step
+ +

D - Functions

+ +

This appendix provides a reference for all of the CUPS API functions. + +

cupsAddOption()

+ +

Usage

+ +
+int
+cupsAddOption(const char *name,
+              const char *value,
+              int num_options,
+	      cups_option_t **options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
nameThe name of the option.
valueThe value of the option.
num_optionsNumber of options currently in the array.
optionsPointer to the options array.
+ +

Returns

+ +

The new number of options. + +

Description

+ +

cupsAddOption() adds an option to the specified array. + +

Example

+ +
+#include <cups.h>
+
+...
+
+/* Declare the options array */
+int           num_options;
+cups_option_t *options;
+
+/* Initialize the options array */
+num_options = 0;
+options     = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption("media", "letter", num_options, &options);
+num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
+
+ +

See Also

+ +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + +

cupsCancelJob()

+ +

Usage

+ +
+int
+cupsCancelJob(const char *dest,
+              int job);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
destPrinter or class name
jobJob ID
+ +

Returns

+ +

1 on success, 0 on failure. On failure the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsCancelJob() cancels the specifies job. + +

Example

+ +
+#include <cups.h>
+
+cupsCancelJob("LaserJet", 1);
+
+ +

See Also

+ +

+cupsLastError(), +cupsPrintFile() + +

cupsDoFileRequest()

+ +

Usage

+ +
+ipp_t *
+cupsDoFileRequest(http_t *http,
+                  ipp_t *request,
+                  const char *resource,
+		  const char *filename);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
filenameFile to send with POST request (NULL pointer if none.)
+ +

Returns

+ +

IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsDoFileRequest() does a HTTP POST request and provides the +IPP request and optionally the contents of a file to the IPP server. It also +handles resubmitting the request and performing password authentication as +needed. + +

Example

+ +
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_PRINT_FILE;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+             "attributes-charset", NULL, cupsLangEncoding(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+             "attributes-natural-language", NULL,
+             language != NULL ? language->language : "C");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+             NULL, "ipp://hostname/resource");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+             NULL, cupsUser());
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + +

cupsDoRequest()

+ +

Usage

+ +
+ipp_t *
+cupsDoRequest(http_t *http,
+              ipp_t *request,
+              const char *resource);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
+ +

Returns

+ +

IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsDoRequest() does a HTTP POST request and provides +the IPP request to the IPP server. It also handles resubmitting the +request and performing password authentication as needed. + +

Example

+ +
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+             "attributes-charset", NULL, cupsLangEncoding(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+             "attributes-natural-language", NULL,
+             language != NULL ? language->language : "C");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+             NULL, "ipp://hostname/resource");
+
+/* Do the request... */
+response = cupsDoRequest(http, request, "/resource");
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + +

cupsFreeOptions()

+ +

Usage

+ +
+void
+cupsFreeOptions(int num_options,
+                cups_option_t *options);
+
+

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
num_optionsNumber of options in array.
optionsPointer to options array.
+ +

Description

+ +

cupsFreeOptions() frees all memory associated with the +option array specified. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsGetOption(), +cupsMarkOptions(), +cupsParseOptions() + +

cupsGetClasses()

+ +

Usage

+ +
+int
+cupsGetClasses(char ***classes);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
classesPointer to character pointer array.
+ +

Returns

+ +

The number of printer classes available. + +

Description

+ +

cupsGetClasses() gets a list of the available printer classes. +The returned array should be freed using the free() when it is +no longer needed. + +

Example

+ +
+#include <cups/cups.h>
+
+int  i;
+int  num_classes;
+char **classes;
+
+...
+
+num_classes = cupsGetClasses(&classes);
+
+...
+
+if (num_classes > 0)
+{
+  for (i = 0; i < num_classes; i ++)
+    free(classes[i]);
+
+  free(classes);
+}
+
+ +

See Also

+ +

+cupsGetDefault(), +cupsGetPrinters() + +

cupsGetDefault()

+ +

Usage

+ +
+const char *
+cupsGetDefault(void);
+
+ +

Returns

+ +

A pointer to the default destination. + +

Description

+ +

cupsGetDefault() gets the default destination printer or class. +The default destination is stored in a static string and will be overwritten +(usually with the same value) after each call. + +

Example

+ +
+#include <cups/cups.h>
+
+printf("The default destination is %s\n", cupsGetDefault());
+
+ +

See Also

+ +

+cupsGetClasses(), +cupsGetPrinters() + +

cupsGetOption()

+ +

Usage

+ +
+const char *
+cupsGetOption(const char *name,
+              int num_options,
+              cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
nameThe name of the option.
num_optionsThe number of options in the array.
optionsThe options array.
+ +

Returns

+ +

A pointer to the option values or NULL if the option is +not defined. + +

Description

+ +

cupsGetOption() returns the first occurrence of the +named option. If the option is not included in the options array then a +NULL pointer is returned. + +

+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+const char    *media;
+
+...
+
+media = cupsGetOption("media", num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsMarkOptions(), +cupsParseOptions() + +

cupsGetPassword()

+ +

Usage

+ +
+const char *
+cupsGetPassword(const char *prompt);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
promptThe prompt to display to the user.
+ +

Returns

+ +

A pointer to the password that was entered or NULL if no +password was entered. + +

Description

+ +

cupsGetPassword() displays the prompt string and asks the user +for a password. The password text is not echoed to the user. + +

Example

+ +
+#include <cups/cups.h>
+
+char *password;
+
+...
+
+password = cupsGetPassword("Please enter a password:");
+
+ +

See Also

+ +

+cupsServer(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + +

cupsGetPPD()

+ +

Usage

+ +
+const char *
+cupsGetPPD(const char *printer);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
printerThe name of the printer.
+ +

Returns

+ +

The name of a temporary file containing the PPD file or NULL +if the printer cannot be located or does not have a PPD file. + +

Description

+ +

cupsGetPPD() gets a copy of the PPD file for the named printer. +The printer name can be of the form "printer" or "printer@hostname". + +

You should remove (unlink) the PPD file after you are done using it. The +filename is stored in a static buffer and will be overwritten with each call +to cupsGetPPD(). + +

Example

+ +
+#include <cups/cups.h>
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD("printer@hostname");
+
+...
+
+unlink(ppd);
+
+ +

cupsGetPrinters()

+ +

Usage

+ +
+int
+cupsGetPrinters(char ***printers);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
printersPointer to character pointer array.
+ +

Returns

+ +

The number of printer printers available. + +

Description

+ +

cupsGetPrinters() gets a list of the available printers. +The returned array should be freed using the free() when it is +no longer needed. + +

Example

+ +
+#include <cups/cups.h>
+
+int  i;
+int  num_printers;
+char **printers;
+
+...
+
+num_printers = cupsGetPrinters(&printers);
+
+...
+
+if (num_printers > 0)
+{
+  for (i = 0; i < num_printers; i ++)
+    free(printers[i]);
+
+  free(printers);
+}
+
+ +

See Also

+ +

+cupsGetClasses(), +cupsGetDefault() + +

cupsLangDefault()

+ +

Usage

+ +
+const char *
+cupsLangDefault(void);
+
+ +

Returns

+ +

A pointer to the default language structure. + +

Description

+ +

cupsLangDefault() returns a language structure for the default +language. The default language is defined by the LANG environment +variable. If the specified language cannot be located then the POSIX (English) +locale is used. + +

Call cupsLangFree() to free any memory associated with the +language structure when you are done. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangEncoding()

+ +

Usage

+ +
+char *
+cupsLangEncoding(cups_lang_t *language);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
languageThe language structure.
+ +

Returns

+ +

A pointer to the encoding string. + +

Description

+ +

cupsLangEncoding() returns the language encoding used for the +specified language, e.g. "iso-8859-1", "utf-8", etc. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangFlush()

+ +

Usage

+ +
+void
+cupsLangFlush(void);
+
+ +

Description

+ +

cupsLangFlush() frees all language structures that have been +allocated. + +

Example

+ +
+#include <cups/language.h>
+
+...
+
+cupsLangFlush();
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangFree()

+ +

Usage

+ +
+void
+cupsLangFree(cups_lang_t *language);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
languageThe language structure to free.
+ +

Description

+ +

cupsLangFree() frees the specified language structure. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangGet(), +cupsLangString() + +

cupsLangGet()

+ +

Usage

+ +
+cups_lang_t *
+cupsLangGet(const char *name);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
nameThe name of the locale.
+ +

Returns

+ +

A pointer to a language structure. + +

Description

+ +

cupsLangGet() returns a language structure for the specified +locale. If the locale is not defined then the POSIX (English) locale is +substituted. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet("fr");
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangString() + +

cupsLangString()

+ +

Usage

+ +
+char *
+cupsLangString(cups_lang_t *language,
+               int         message);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
languageThe language to query.
messageThe message number.
+ +

Returns

+ +

A pointer to the message string or NULL if the message is +not defined. + +

Description

+ +

cupsLangString() returns a pointer to the specified message +string in the specified language. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *s;
+...
+
+language = cupsLangGet("fr");
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet() + +

cupsLastError()

+ +

Usage

+ +
+ipp_status_t
+cupsLastError(void);
+
+ +

Returns

+ +

An enumeration containing the last IPP error. + +

Description

+ +

cupsLastError() returns the last IPP error that occurred. +If no error occurred then it will return IPP_OK or +IPP_OK_CONFLICT. + +

Example

+ +
+#include <cups/cups.h>
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+
+ +

See Also

+ +

+cupsCancelJob(), +cupsPrintFile() + +

cupsMarkOptions()

+ +

Usage

+ +
+int
+cupsMarkOptions(ppd_file_t *ppd,
+                int num_options,
+                cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file to mark.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+ +

Returns

+ +

The number of conflicts found. + +

Description

+ +

cupsMarkOptions() marks options in the PPD file. It also +handles mapping of IPP option names and values to PPD option names. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+ppd_file_t    *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + +

cupsParseOptions()

+ +

Usage

+ +
+int
+cupsParseOptions(const char *arg,
+                 int num_options,
+                 cups_option_t **options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
argThe string containing one or more options.
num_optionsThe number of options in the options array.
optionsA pointer to the options array pointer.
+ +

Returns

+ +

The new number of options in the array. + +

Description

+ +

cupsParseOptions() parses the specifies string for one +or more options of the form "name=value", "name", or "noname". It can +be called multiple times to combine the options from several strings. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options     = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsMarkOptions() + +

cupsPrintFile()

+ +

Usage

+ +
+int
+cupsPrintFile(const char    *printer,
+              const char    *filename,
+              const char    *title,
+	      int           num_options,
+	      cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
filenameThe file to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+ +

Returns

+ +

The new job ID number or 0 on error. + +

Description

+ +

cupsPrintFile() sends a file to the specified printer or +class for printing. If the job cannot be printed the error code can be +found by calling cupsLastError(). + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+int           jobid;
+
+...
+
+jobid = cupsPrintFile("printer@hostname", "filename.ps", "Job Title",
+                      num_options, options);
+
+ +

See Also

+ +

+cupsCancelJob(), +cupsLastError(), +cupsPrintFiles() + +

cupsPrintFiles()

+ +

Usage

+ +
+int
+cupsPrintFiles(const char    *printer,
+               int           num_files,
+               const char    **files,
+               const char    *title,
+	       int           num_options,
+	       cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
num_filesThe number of files to print.
filesThe files to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+ +

Returns

+ +

The new job ID number or 0 on error. + +

Description

+ +

cupsPrintFiles() sends multiple files to the specified +printer or class for printing. If the job cannot be printed the error +code can be found by calling cupsLastError(). + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_files;
+const char    *files[100];
+int           num_options;
+cups_option_t *options;
+int           jobid;
+
+...
+
+jobid = cupsPrintFiles("printer@hostname", num_files, files,
+                       "Job Title", num_options, options);
+
+ +

See Also

+ +

+cupsCancelJob(), +cupsLastError(), +cupsPrintFile() + +

cupsRasterClose()

+ +

Usage

+ +
+void
+cupsRasterClose(cups_raster_t *ras);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
rasThe raster stream to close.
+ +

Description

+ +

cupsRasterClose() closes the specified raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+
+ +

See Also

+ +

+cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

cupsRasterOpen()

+ +

Usage

+ +
+cups_raster_t *
+cupsRasterOpen(int fd,
+               cups_mode_t mode);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
fdThe file descriptor to use.
modeThe mode to use; CUPS_RASTER_READ or + CUPS_RASTER_WRITE.
+ +

Returns

+ +

A pointer to a raster stream or NULL if there was an error. + +

Description

+ +

cupsRasterOpen() opens a raster stream for reading or writing. + +

Example

+ +
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterReadHeader()

+ +

Usage

+ +
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+                     cups_page_header_t *header);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to read from.
headerA pointer to a page header structure to read into.
+ +

Returns

+ +

1 on success, 0 on EOF or error. + +

Description

+ +

cupsRasterReadHeader() reads a page header from the specified +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterReadPixels()

+ +

Usage

+ +
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+                     unsigned char *pixels,
+		     unsigned length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to read from.
pixelsThe pointer to a pixel buffer.
lengthThe number of bytes of pixel data to read.
+ +

Returns

+ +

The number of bytes read or 0 on EOF or error. + +

Description

+ +

cupsRasterReadPixels() reads pixel data from the specified +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterWriteHeader()

+ +

Usage

+ +
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+                      cups_page_header_t *header);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to write to.
headerA pointer to the page header to write.
+ +

Returns

+ +

1 on success, 0 on error. + +

Description

+ +

cupsRasterWriteHeader() writes the specified page header to +a raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + +

cupsRasterWritePixels()

+ +

Usage

+ +
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+                      unsigned char *pixels,
+		      unsigned length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to write to.
pixelsThe pixel data to write.
lengthThe number of bytes to write.
+ +

Returns

+ +

The number of bytes written. + +

Description

+ +

cupsRasterWritePixels() writes the specified pixel data to a +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + +

cupsServer()

+ +

Usage

+ +
+const char *
+cupsServer(void);
+
+ +

Returns

+ +

A pointer to the default server name. + +

Description

+ +

cupsServer() returns a pointer to the default server name. +The server name is stored in a static location and will be overwritten with +every call to cupsServer() + +

The default server is determined from the following locations: + +

    + +
  1. The CUPS_SERVER environment variable, + +
  2. The ServerName directive in the + client.conf file, + +
  3. The default host, "localhost". + +
+ +

Example

+ +
+#include <cups/cups.h>
+
+const char *server;
+
+server = cupsServer();
+
+ +

See Also

+ +

+cupsGetPassword(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + +

cupsSetPasswordCB()

+ +

Usage

+ +
+void
+cupsSetPasswordCB(const char *(*cb)(const char *prompt));
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
cbThe password callback function.
+ +

Description

+ +

cupsSetPasswordCB() sets the callback function to use when +asking the user for a password. The callback function must accept a single +character string pointer (the prompt string) and return NULL +if the user did not enter a password string or a pointer to the password +string otherwise. + +

Example

+ +
+#include <cups/cups.h>
+
+const char *
+my_password_cb(const char *prompt)
+{
+  return (getpass(prompt));
+}
+
+...
+
+char *password;
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+password = cupsGetPassword("Please enter a password:");
+
+ +

See Also

+ +

+cupsServer(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + +

cupsSetServer()

+ +

Usage

+ +
+void
+cupsSetServer(const char *server);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
serverThe default server to use.
+ +

Description

+ +

cupsSetServer() sets the default server to use for +the CUPS API. If the server argument is NULL, +the default server is used. + +

Example

+ +
+#include <cups/cups.h>
+
+cupsSetServer("foo.bar.com");
+
+ +

See Also

+ +

+cupsServer(), +cupsSetPasswordCB(), +cupsSetUser(), +cupsUser() + +

cupsSetUser()

+ +

Usage

+ +
+void
+cupsSetUser(const char *user);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
userThe user name string to use.
+ +

Description

+ +

cupsSetUser() sets the default user name for authentication. +If the user argument is NULL then the current +login user is used. + +

Example

+ +
+#include <cups/cups.h>
+
+...
+
+cupsSetUser("root");
+
+ +

See Also

+ +

+cupsServer(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsUser() + +

cupsTempFile()

+ +

Usage

+ +
+char *
+cupsTempFile(char *filename,
+             int length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
filenameThe character string to hold the temporary filename.
lengthThe size of the filename string in bytes.
+ +

Returns

+ +

A pointer to filename. + +

Description

+ +

cupsTempFile() generates a temporary filename for the +/var/tmp directory or the directory specified by the +TMPDIR environment variable. + +

Example

+ +
+#include <cups/cups.h>
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+
+ +

cupsUser()

+ +

Usage

+ +
+const char *
+cupsUser(void);
+
+ +

Returns

+ +

A pointer to the current username or NULL if the user ID is +undefined. + +

Description

+ +

cupsUser() returns the name associated with the current +user ID as reported by the getuid() system call. + +

Example

+ +
+#include <cups/cups.h>
+
+const char *user;
+
+user = cupsUser();
+
+ +

See Also

+ +

+cupsGetPassword(), +cupsServer() + +

httpBlocking()

+ +

Usage

+ +
+void httpBlocking(http_t *http, int blocking)
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
blocking0 if the connection should be non-blocking, 1 if it should + be blocking
+ +

Description

+ +

The httpBlocking() function sets the blocking mode for the +HTTP connection. By default HTTP connections will block (stop) the client +program until data is available or can be sent to the server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+http = httpConnect("server", port);
+httpBlocking(http, 0);
+
+ +

See Also

+ +httpCheck(), +httpConnect() + +

httpCheck()

+ +

Usage

+ +
+int httpCheck(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Returns

+ +

0 if there is no data pending, 1 otherwise. + +

Description

+ +

The httpCheck() function checks to see if there is any data +pending on an HTTP connection. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+if (httpCheck(http))
+{
+  ... do something ...
+}
+
+ +

See Also

+ +httpBlocking(), +httpConnect(), +httpGets(), +httpRead() + + +

httpClearFields()

+ +

Usage

+ +
+void httpClearFields(http_t *http)
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Description

+ +

The httpClearFields() function clears all HTTP request fields +for the HTTP connection. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpClearFields(http);
+
+ +

See Also

+ +httpConnect(), +httpGetField(), +httpSetField() + +

httpClose()

+ +

Usage

+ +
+void httpClose(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Description

+ +

The httpClose() function closes an active HTTP connection. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpClose(http);
+
+ +

See Also

+ +httpConnect() + +

httpConnect()

+ +

Usage

+ +
+http_t *httpConnect(const char *hostname, int port);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
hostnameThe name or IP address of the server to connect to
portThe port number to use
+ +

Returns

+ +

A pointer to a HTTP connection structure or NULL if the connection could +not be made. + +

Description

+ +

The httpConnect() function opens a HTTP connection to the +specified server and port. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+
+ +

See Also

+ +httpClose(), +httpGet(), +httpGets(), +httpPost(), +httpRead(), +httpWrite() + + +

httpDecode64()

+ +

Usage

+ +
+char *httpDecode64(char *out, const char *in);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
outThe output string
inThe input string
+ +

Returns

+ +

A pointer to the decoded string. + +

Description

+ +

The httpDecode64() function decodes a base-64 encoded string +to the original string. + +

Example

+ +
+#include <cups/http.h>
+
+char encoded_string[255];
+char original_string[255];
+
+httpDecode64(original_string, encoded_string);
+
+ +

See Also

+ +httpEncode64() + +

httpDelete()

+ +

Usage

+ +
+int httpDelete(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to delete
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpDelete() function sends a HTTP DELETE request to +the server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + +

httpEncode64()

+ +

Usage

+ +
+char *httpEncode64(char *out, const char *in);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
outThe output string
inThe input string
+ +

Returns

+ +

A pointer to the encoded string. + +

Description

+ +

The httpEncode64() function decodes a base-64 encoded string +to the original string. + +

Example

+ +
+#include <cups/http.h>
+
+char encoded_string[255];
+char original_string[255];
+
+httpEncode64(encoded_string, original_string);
+
+ +

See Also

+ +httpDecode64() + +

httpError()

+ +

Usage

+ +
+int httpError(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Returns

+ +

The last error that occurred or 0 if no error has occurred. + +

Description

+ +

The httpError() function returns the last error that occurred +on the HTTP connection. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+if (httpError(http))
+{
+  ... show an error message ...
+}
+
+ +

See Also

+ +httpConnect() + +

httpFlush()

+ +

Usage

+ +
+void httpFlush(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Description

+ +

The httpFlush() function flushes any remaining data left from +a GET or POST operation. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpFlush(http);
+
+ +

See Also

+ +httpConnect(), + +

httpGet()

+ +

Usage

+ +
+int httpGet(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to get
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpGet() function sends a HTTP GET request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpGets()

+ +

Usage

+ +
+char *httpGets(char *line, int length, http_t *http)
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
lineThe string to fill with a line from the HTTP connection
lengthThe maximum length of the string
httpThe HTTP connection
+ +

Returns

+ +

A pointer to the string or NULL if no line could be retrieved. + +

Description

+ +

The httpGets() function is used to read a request line from +the HTTP connection. It is not normally used by a client program. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+char line[1024];
+
+if (httpGets(line, sizeof(line), http))
+{
+  ... process the line ...
+}
+
+ +

See Also

+ +httpConnect(), +httpUpdate() + +

httpGetDateString()

+ +

Usage

+ +
+const char *httpGetDateString(time_t time)
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
timeThe UNIX date/time value
+ +

Returns

+ +

A pointer to a static string containing the HTTP date/time string for +the specified UNIX time value. + +

Description

+ +

The httpGetDateString() function generates a date/time string +suitable for HTTP requests from a UNIX time value. + +

Example

+ +
+#include <cups/http.h>
+
+puts(httpGetDateString(time(NULL)));
+
+ +

See Also

+ +httpGetDateTime() + + +

httpGetDateTime()

+ +

Usage

+ +
+time_t httpGetDateTime(const char *date)
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
dateThe HTTP date/time string
+ +

Returns

+ +

A UNIX time value. + +

Description

+ +

The httpGetDateTime() function converts a HTTP +date/time string to a UNIX time value. + +

Example

+ +
+#include <cups/http.h>
+
+printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
+
+ +

See Also

+ +httpGetDateString() + + +

httpGetField()

+ +

Usage

+ +
+const char *httpGetField(http_t *http, http_field_t field);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
fieldThe HTTP field
+ +

Returns

+ +

A pointer to the field value string. + +

Description

+ +

The httpGetField() function returns the current value for +the specified HTTP field. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
+
+ +

See Also

+ +httpConnect(), +httpSetField() + + +

httpHead()

+ +

Usage

+ +
+int httpHead(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to head
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpHead() function sends a HTTP HEAD request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpHead(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpInitialize()

+ +

Usage

+ +
+void httpInitialize(void);
+
+ +

Description

+ +

The httpInitialize() function initializes the networking +code as needed by the underlying platform. It is called automatically by +the httpConnect() function. + +

Example

+ +
+#include <cups/http.h>
+
+httpInitialize();
+
+ +

See Also

+ +httpConnect() + +

httpOptions()

+ +

Usage

+ +
+int httpOptions(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to check for options
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpOptions() function sends a HTTP OPTIONS request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpOptions(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpPost()

+ +

Usage

+ +
+int httpPost(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to post to
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpPost() function sends a HTTP POST request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpPost(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpPrintf()

+ +

Usage

+ +
+int httpPrintf(http_t *http, const char *format, ...);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
formatA printf-style format string
+ +

Returns

+ +

The number of bytes written. + +

Description

+ +

The httpPrintf() function sends a formatted string to the +HTTP connection. It is normally only used by the CUPS API and scheduler. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpPrintf(http, "GET / HTTP/1.1 \r\n");
+
+ +

See Also

+ +httpConnect() + +

httpPut()

+ +

Usage

+ +
+int httpPut(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to put
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpPut() function sends a HTTP PUT request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpRead()

+ +

Usage

+ +
+int httpRead(http_t *http, char *buffer, int length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
bufferThe buffer to read into
lengthThe number of bytes to read
+ +

Returns

+ +

The number of bytes read or -1 on error. + +

Description

+ +

The httpRead() function reads data from the HTTP connection, +possibly the result of a GET or POST request. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+char buffer[1024];
+int  bytes;
+
+httpGet(http, "/");
+while (httpUpdate(http) != HTTP_CONTINUE);
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+  buffer[bytes] = '\0';
+  fputs(buffer, stdout);
+}
+
+ +

See Also

+ +httpConnect(), +httpWrite() + +

httpReconnect()

+ +

Usage

+ +
+int httpReconnect(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpReconnect() function reconnects to the HTTP server. +This is usually done automatically if the HTTP functions detect that the +server connection has terminated. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpReconnect(http);
+
+ +

See Also

+ +httpConnect() + +

httpSeparate()

+ +

Usage

+ +
+void httpSeparate(const char *uri, char *method,
+                  char *username, char *host, int *port,
+                  char *resource);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
uriThe URI to separate
methodThe method (scheme) of the URI
usernameThe username (and password) portion of the URI, if any
hostThe hostname portion of the URI, if any
portThe port number for the URI, either as specified or as + default for the method/scheme
resourceThe resource string, usually a filename on the server
+ +

Description

+ +

The httpSeparate() function separates the specified URI into +its component parts. The method, username, hostname, and resource strings should +be at least HTTP_MAX_URI characters long to avoid potential +buffer overflow problems. + +

Example

+ +
+char uri[HTTP_MAX_URI];
+char method[HTTP_MAX_URI];
+char username[HTTP_MAX_URI];
+char host[HTTP_MAX_URI];
+char resource[HTTP_MAX_URI];
+int port;
+
+httpSeparate(uri, method, username, host, &port, resource);
+
+ +

See Also

+ +httpConnect() + +

httpSetField()

+ +

Usage

+ +
+void httpSetField(http_t *http, http_field_t field, const char *value);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
fieldThe HTTP field
valueThe string value for the field
+ +

Description

+ +

The httpSetField() function sets the current value for +the specified HTTP field. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpSetField(http, HTTP_FIELD_AUTHORIZATION, "Basic dfdr34453454325"));
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+ +

See Also

+ +httpConnect(), +httpGetField() + + +

httpTrace()

+ +

Usage

+ +
+int httpTrace(http_t *http, const char *uri);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
uriThe URI to trace
+ +

Returns

+ +

0 on success, non-zero on failure. + +

Description

+ +

The httpTrace() function sends a HTTP TRACE request to the +server. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+
+httpTrace(http, "/some/uri");
+
+ +

See Also

+ +httpConnect(), +httpSetField(), +httpUpdate() + + +

httpUpdate()

+ +

Usage

+ +
+http_status_t httpUpdate(http_t *http);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
httpThe HTTP connection
+ +

Returns

+ +

The HTTP status of the current request. + +

Description

+ +

The httpUpdate() function updates the current request status. +It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or TRACE +request to finalize the HTTP request and retrieve the request status. + +

Since proxies and the current blocking mode can cause the request to +take longer, programs should continue calling httpUpdate() +until the return status is not the constant value HTTP_CONTINUE. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+http_status_t status;
+
+httpGet(http, "/some/uri");
+while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+printf("Request status is %d\n", status);
+
+ +

See Also

+ +httpConnect(), +httpDelete(), +httpGet(), +httpHead(), +httpOptions(), +httpPost(), +httpPut(), +httpTrace() + +

httpWrite()

+ +

Usage

+ +
+int httpWrite(http_t *http, char *buffer, int length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
bufferThe buffer to read into
lengthThe number of bytes to read
+ +

Returns

+ +

The number of bytes read or -1 on error. + +

Description

+ +

The httpWrite() function reads data from the HTTP connection, +possibly the result of a GET or POST request. + +

Example

+ +
+#include <cups/http.h>
+
+http_t *http;
+FILE *fp;
+char buffer[1024];
+int  bytes;
+
+httpPost(http, "/");
+
+while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+  httpWrite(http, buffer, bytes);
+
+while (httpUpdate(http) != HTTP_CONTINUE);
+
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+  buffer[bytes] = '\0';
+  fputs(buffer, stdout);
+}
+
+ +

See Also

+ +httpConnect(), +httpRead() + +

ippAddBoolean()

+ +

Usage

+ +
+ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
+                               const char *name, char value);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
valueThe boolean value
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddBoolean() function adds a single boolean attribute +value to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
+
+ +

See Also

+ +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddBooleans()

+ +

Usage

+ +
+ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
+                                const char *name, int num_values,
+                                const char *values);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of values
valuesThe boolean values
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddBooleans() function adds one or more boolean +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values false values is created. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+char values[10];
+
+ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddDate()

+ +

Usage

+ +
+ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
+                            const char *name, ipp_uchar_t *value);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
valueThe date value
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddDate() function adds a single date-time attribute +value to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute", 
+           ippTimeToDate(time(NULL));
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings(), +ippTimeToDate() + + +

ippAddInteger()

+ +

Usage

+ +
+ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
+                               ipp_tag_t tag, const char *name,
+                               int value);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)
nameThe name of attribute
valueThe integer value
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddInteger() function adds a single integer attribute +value to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddIntegers()

+ +

Usage

+ +
+ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
+                                ipp_tag_t tag, const char *name,
+                                int num_values, const int *values);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)
nameThe name of attribute
num_valuesThe number of values
valuesThe integer values
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddIntegers() function adds one or more integer +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0 values is created. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int values[100];
+
+ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddRange()

+ +

Usage

+ +
+ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
+                             const char *name, int low,
+                             int high);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
lowThe lower value
highThe higher value
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddRange() function adds a single range attribute +value to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddRanges()

+ +

Usage

+ +
+ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
+                              const char *name, int num_values,
+                              const int *lows, const int *highs);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of range values
lowsThe lower values
highsThe higher values
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddRanges() function adds one or more range +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 ranges is created. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int lows[2];
+int highs[2];
+
+ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddResolution()

+ +

Usage

+ +
+ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
+                                  const char *name, int xres,
+                                  int yres, ipp_res_t units);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
xresThe horizontal resolution
yresThe vertical resolution
unitsThe resolution units
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddResolution() function adds a single resolution attribute +value to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
+              720, 720, IPP_RES_PER_INCH);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddResolutions()

+ +

Usage

+ +
+ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
+                                   const char *name, int num_values,
+                                   const int *xres, const int *yres,
+                                   const ipp_res_t *units);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
nameThe name of attribute
num_valuesThe number of resolution values
xresThe horizontal resolutions
yresThe vertical resolutions
unitsThe resolution units
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddResolutions() function adds one or more +resolution attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 resolutions is created. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+int xres[5];
+int yres[5];
+ipp_res_t units[5];
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolutions-supported",
+              5, xres, yres, units);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

ippAddSeparator()

+ +

Usage

+ +
+ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ippThe IPP request
+ +

Returns

+ +

A pointer to the new separator or NULL if the separator could not be +created. + +

Description

+ +

The ippAddSeparator() function adds a group separator +to the specified IPP request. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddSeparator(ipp);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddString(), +ippAddStrings() + + +

ippAddString()

+ +

Usage

+ +
+ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
+                              ipp_tag_t tag, const char *name,
+                              const char *charset, const char *value);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of string value
nameThe name of attribute
charsetThe character set for the string
valueThe string value
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddString() function adds a single string attribute +value to the specified IPP request. For IPP_TAG_NAMELANG and +IPP_TAG_TEXTLANG strings, the charset value is provided with +the string to identify the string encoding used. Otherwise the charset value +is ignored. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+             NULL, "abc123");
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddStrings() + + +

ippAddStrings()

+ +

Usage

+ +
+ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
+                               ipp_tag_t tag, const char *name,
+                               int num_values, const char *charset,
+                               const char **values);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request
groupThe IPP group
tagThe type of string value
nameThe name of attribute
num_valuesThe number of strings
charsetThe character set for the strings
valuesThe string values
+ +

Returns

+ +

A pointer to the new attribute or NULL if the attribute could not be +created. + +

Description

+ +

The ippAddStrings() function adds one or more string +attribute values to the specified IPP request. For +IPP_TAG_NAMELANG and IPP_TAG_TEXTLANG +strings, the charset value is provided with the strings to identify the +string encoding used. Otherwise the charset value is ignored. If the +values pointer is NULL then an array of +num_values NULL strings is created. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+char *values[2] = { "one", "two" };
+
+ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
+              2, NULL, values);
+
+ +

See Also

+ +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString() + + +

ippDateToTime()

+ +

Usage

+ +
+time_t ippDateToTime(const ipp_uchar_t date[11]);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
dateThe IPP date-time value
+ +

Returns

+ +

A UNIX time value. + +

Description

+ +

The ippDateToTime() function converts an IPP date-time value +to a UNIX time value. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_uchar_t date[11];
+
+printf("UNIX time is %d\n", ippDateToTime(date));
+
+ +

See Also

+ +ippTimeToDate() + + +

ippDelete()

+ +

Usage

+ +
+void ippDelete(ipp_t *ipp);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ippThe IPP request or response
+ +

Description

+ +

The ippDelete() function deletes all memory used by an IPP +request or response. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ippDelete(ipp);
+
+ +

See Also

+ +ippNew() + + +

ippFindAttribute()

+ +

Usage

+ +
+ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t tag);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ippThe IPP request or response
nameThe name of the attribute
tagThe required value tag for the attribute or + IPP_TAG_ZERO for any type of value.
+ +

Returns

+ +

A pointer to the first occurrence of the requested attribute, or +NULL if it was not found. + +

Description

+ +

ippFindAttribute() finds the first occurrence of the named +attribute. The tag parameter restricts the search to a specific +value type - use IPP_TAG_ZERO to find any value with the name. + +

The value tags IPP_TAG_NAME and IPP_TAG_TEXT +match the name/text values with or without the language code. + +

Example

+ +
+ipp_attribute_t *attr;
+
+attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
+
+ +

See Also

+ +cupsDoFileRequest(), +cupsDoRequest(), +ippDelete(), +ippNew() + + +

ippLength()

+ +

Usage

+ +
+int ippLength(ipp_t *ipp);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ippThe IPP request or response
+ +

Returns

+ +

The total encoded length of the IPP request or response in bytes. + +

Description

+ +

ippLength() returns the length of the IPP request or +response in bytes. + +

Example

+ +
+printf("The length of the response is %d bytes.\n", ippLength(response));
+
+ +

See Also

+ +ippDelete(), +ippNew() + + +

ippNew()

+ +

Usage

+ +
+ipp_t *ippNew(void);
+
+ +

Returns

+ +

A pointer to a new IPP request or response. + +

Description

+ +

The ippNew() function creates a new IPP request or response. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_t *ipp;
+
+ipp = ippNew();
+
+ +

See Also

+ +ippDelete() + + +

ippPort()

+ +

Usage

+ +
+int ippPort(void);
+
+ +

Returns

+ +

The default TCP/IP port number for IPP requests. + +

Description

+ +

The ippPort() function returns the default IPP port number +for requests. + +

Example

+ +
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+
+ +

See Also

+ +cupsServer(), +ippSetPort() + + +

ippRead()

+ +

Usage

+ +
+ipp_state_t ippRead(http_t *http, ipp_t *ipp);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
ippThe IPP request or response
+ +

Returns

+ +

The current read state. + +

Description

+ +

The ippRead() function reads IPP attributes from the specified +HTTP connection. Programs should continue calling ippRead() until +IPP_ERROR or IPP_DATA is returned. + +

Example

+ +
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+
+while ((status = ippRead(http, ipp)) != IPP_ERROR)
+  if (status == IPP_DATA)
+    break;
+
+if (status == IPP_DATA)
+{
+  ... read additional non-IPP data using httpRead() ...
+}
+
+ +

See Also

+ +ippWrite() + + +

ippSetPort()

+ +

Usage

+ +
+void
+ippSetPort(int port);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
portThe port number to use
+ +

Description

+ +

The ippSetPort() function sets the default IPP port number +for requests. + +

Example

+ +
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+...
+
+ippSetPort(8631);
+
+ +

See Also

+ +ippPort() + + +

ippTimeToDate()

+ +

Usage

+ +
+ipp_uchar_t *ippTimeToDate(time_t time);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
timeThe UNIX time value
+ +

Returns

+ +

A static pointer to an IPP date-time value. + +

Description

+ +

The ippTimeToDate() function converts a UNIX time to an IPP +date-time value. + +

Example

+ +
+#include <cups/ipp.h>
+
+ipp_uchar_t *date;
+
+date = ippTimeToDate(time(NULL));
+
+ +

See Also

+ +ippDateToTime() + + +

ippWrite()

+ +

Usage

+ +
+ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
httpThe HTTP connection
ippThe IPP request or response
+ +

Returns

+ +

The current write state. + +

Description

+ +

The ippWrite() function writes IPP attributes to the specified +HTTP connection. Programs should continue calling ippWrite() until +IPP_ERROR or IPP_DATA is returned. + +

Example

+ +
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+... add attributes ...
+
+while ((status = ippWrite(http, ipp)) != IPP_ERROR)
+  if (status == IPP_DATA)
+    break;
+
+if (status == IPP_DATA)
+{
+  ... read additional non-IPP data using httpWrite() ...
+}
+
+ +

See Also

+ +ippRead() + + +

ppdClose()

+ +

Usage

+ +
+void ppdClose(ppd_file_t *ppd);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ppdThe PPD file
+ +

Description

+ +

The ppdClose() function frees all memory associated with the +PPD file. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdClose(ppd);
+
+ +

See Also

+ +ppdOpen(), +ppdOpenFd(), +ppdOpenFile() + + +

ppdConflicts()

+ +

Usage

+ +
+int ppdConflicts(ppd_file_t *ppd);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ppdThe PPD file
+ +

Returns

+ +

The number of option conflicts in the file. + +

Description

+ +

The ppdConflicts() function returns the number of conflicts +with the currently selected options. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("%d conflicts\n", ppdConflicts(ppd));
+
+ +

See Also

+ +cupsMarkOptions(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdEmit()

+ +

Usage

+ +
+int ppdEmit(ppd_file_t *ppd, FILE *file, ppd_section_t section);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
fileThe file to write to
sectionThe option section to write
+ +

Returns

+ +

0 on success, -1 on error. + +

Description

+ +

The ppdEmit() function sends printer-specific option +commands to the specified file. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+ +

See Also

+ +ppdEmitFd() + + +

ppdEmitFd()

+ +

Usage

+ +
+int ppdEmitFd(ppd_file_t *ppd, int fd, ppd_section_t section);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
fdThe file descriptor to write to
sectionThe option section to write
+ +

Returns

+ +

0 on success, -1 on error. + +

Description

+ +

The ppdEmitFd() function sends printer-specific option +commands to the specified file descriptor. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
+
+ +

See Also

+ +ppdEmit() + + +

ppdFindChoice()

+ +

Usage

+ +
+ppd_choice_t *ppdFindChoice(ppd_option_t *option, const char *choice);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
optionA pointer to the option
choiceThe name of the choice
+ +

Returns

+ +

A pointer to the choice data or NULL if the choice does not exist. + +

Description

+ +

The ppdFindChoice() function returns a pointer to the choice +data for the specified option. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+ppd_choice_t *choice;
+
+option = ppdFindOption(ppd, "PageSize");
+choice = ppdFindChoice(option, "Letter");
+
+ +

See Also

+ +ppdFindMarkedChoice(), +ppdFindOption() + + +

ppdFindMarkedChoice()

+ +

Usage

+ +
+ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
+ +

Returns

+ +

A pointer to the choice data or NULL if the choice does not exist or +is not marked. + +

Description

+ +

The ppdFindMarkedChoice() function returns a pointer to +the marked choice data for the specified option. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_choice_t *choice;
+
+choice = ppdFindMarkedChoice(ppd, "PageSize");
+
+ +

See Also

+ +ppdFindChoice(), +ppdFindOption() + + +

ppdFindOption()

+ +

Usage

+ +
+ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
+ +

Returns

+ +

A pointer to the option data or NULL if the option does not exist. + +

Description

+ +

The ppdFindOption() function returns a pointer to the option +data for the specified option. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+
+option = ppdFindOption(ppd, "PageSize");
+
+ +

See Also

+ +ppdFindChoice(), +ppdFindMarkedChoice() + + +

ppdIsMarked()

+ +

Usage

+ +
+int ppdIsMarked(ppd_file_t *ppd, const char *keyword, char char *choice);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
choiceThe name of the option choice
+ +

Returns

+ +

1 if the choice is marked, 0 otherwise. + +

Description

+ +

The ppdIsMarked() function returns whether or not the +specified option choice is marked. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Letter size %s selected.\n",
+       ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
+
+ +

See Also

+ +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdMarkDefaults()

+ +

Usage

+ +
+void ppdMarkDefaults(ppd_file_t *ppd);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
ppdThe PPD file
+ +

Description

+ +

The ppdMarkDefaults() function marks all of the default +choices in the PPD file. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkDefaults(ppd);
+
+ +

See Also

+ +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdMarkOption()

+ +

Usage

+ +
+int ppdMarkOption(ppd_file_t *ppd, const char *keyword, const char *choice);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
keywordThe name of the option
choiceThe name of the choice
+ +

Returns

+ +

The number of conflicts in the PPD file. + +

Description

+ +

The ppdMarkOption() function marks the specified option +choice. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkOption(ppd, "PageSize", "Letter");
+
+ +

See Also

+ +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

ppdOpen()

+ +

Usage

+ +
+ppd_file_t *ppdOpen(FILE *file);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
fileThe file to read from
+ +

Returns

+ +

A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

Description

+ +

The ppdOpen() function reads a PPD file from the specified +file into memory. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+FILE *file;
+
+file = fopen("filename.ppd", "rb");
+ppd = ppdOpen(file);
+fclose(file);
+
+ +

See Also

+ +ppdClose(), +ppdOpenFd(), +ppdOpenFile() + + +

ppdOpenFd()

+ +

Usage

+ +
+ppd_file_t *ppdOpenFd(int fd);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
fdThe file descriptor to read from
+ +

Returns

+ +

A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

Description

+ +

The ppdOpenFd() function reads a PPD file from the specified +file descriptor into memory. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+int        fd;
+
+fd = open("filename.ppd", O_RDONLY);
+ppd = ppdOpenFd(fd);
+close(fd);
+
+ +

See Also

+ +ppdClose(), +ppdOpen(), +ppdOpenFile() + + +

ppdOpenFile()

+ +

Usage

+ +
+ppd_file_t *ppdOpenFile(const char *filename);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
filenameThe name of the file to read from
+ +

Returns

+ +

A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

Description

+ +

The ppdOpenFile() function reads a PPD file from the named +file into memory. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile("filename.ppd");
+
+ +

See Also

+ +ppdClose(), +ppdOpen(), +ppdOpenFd() + + +

ppdPageLength()

+ +

Usage

+ +
+float ppdPageLength(ppd_file_t *ppd, const char *name);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+ +

Returns

+ +

The length of the specified page size in points or 0 if the page size +does not exist. + +

Description

+ +

The ppdPageLength() function returns the page length of the +specified page size. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
+
+ +

See Also

+ +ppdPageLength(), +ppdPageSize(), +ppdPageWidth() + + +

ppdPageSize()

+ +

Usage

+ +
+ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+ +

Returns

+ +

A pointer to the page size record of the specified page size in +points or NULL if the page size does not exist. + +

Description

+ +

The ppdPageSize() function returns the page size record for the +specified page size. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+
+size = ppdPageSize(ppd, "Letter");
+if (size != NULL)
+{
+  printf(" Width = %.0f\n", size->width);
+  printf("Length = %.0f\n", size->length);
+  printf("  Left = %.0f\n", size->left);
+  printf(" Right = %.0f\n", size->right);
+  printf("Bottom = %.0f\n", size->bottom);
+  printf("   Top = %.0f\n", size->top);
+}
+
+ +

See Also

+ +ppdPageLength(), +ppdPageWidth() + + +

ppdPageWidth()

+ +

Usage

+ +
+float ppdPageWidth(ppd_file_t *ppd, const char *name);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file
nameThe name of the page size
+ +

Returns

+ +

The width of the specified page size in points or 0 if the page size +does not exist. + +

Description

+ +

The ppdPageWidth() function returns the page width of the +specified page size. + +

Example

+ +
+#include <cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
+
+ +

See Also

+ +ppdPageLength(), +ppdPageSize() + + + + diff --git a/doc/sps.html b/doc/sps.html new file mode 100644 index 0000000000..3a320e8fe7 --- /dev/null +++ b/doc/sps.html @@ -0,0 +1,297 @@ + + + + CUPS Software Performance Specification + + + + + + + +

+

CUPS Software Performance Specification


+CUPS-SPS-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Programs +
+
4 Scheduler Objects +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+

This software performance specification provides an analysis of the +memory, disk, and processor utilitization of each program in the Common +UNIX Printing System ("CUPS") Version 1.1.

+

For the purposes of comparison, all figures are for the Linux Intel +platform. Memory utilization on other platforms should be similar.

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This software performance specification is organized into the +following sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Programs
  • +
  • 4 - Scheduler Objects
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Programs

+

The following table describes the average memory, disk, and CPU +usage of each program in CUPS.

+

The base memory column shows the initial memory requirements for +each program, including any shared libraries that are provided by CUPS.

+

The max memory column shows the maximum amount of memory that will +be used by the program based upon the default configuration settings +supplied with CUPS.

+

The temp files column indicates whether any temporary files are +created.

+

The CPU usage column specifies a relative CPU usage by the program +under normal conditions, either low, medium, or high. Low usage +indicates that the program will never use more than 33% of the +available CPU time. Medium usage indicates the program will use as much +as 66% of the available CPU time. High usage indicates the program uses +66% or more of the available CPU time. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Backends
ProgramBase MemoryMax MemoryTemp +FilesCPU Usage
ipp91k256kUp to size of print file +Low
lpd89k89kUp to size of print file +Low
parallel85k85kUp to size of print +fileLow
serial85k85kUp to size of print file +Low
socket85k85kUp to size of print file +Low
usb85k85kUp to size of print file +Low
CGIs
ProgramBase MemoryMax MemoryTemp +FilesCPU Usage
admin.cgi107k256kUp to size of PPD +fileMedium
classes.cgi95kSize of class objects +NoneMedium
jobs.cgi93kSize of job objectsNone +Medium
printers.cgi95kSize of printer objects +NoneMedium
Command-Line Programs
ProgramBase MemoryMax MemoryTemp +FilesCPU Usage
accept88k128kNoneLow
cancel88k128kNoneLow
disable88k128kNoneLow
enable88k128kNoneLow
lp90k256kNoneLow
lpadmin148k256kNoneLow
lpc86kSize of job and printer objects +NoneMedium
lpinfo89kSize of device and PPD objects +NoneMedium
lpmove88k128kNoneLow
lpoptions89k128kNoneLow
lppasswd90k90kNoneLow
lpq87kSize of job objectsNone +Medium
lpr87k256kNoneLow
lprm84k128kNoneLow
lpstat119kSize of job, printer, and class +objectsNoneMedium
reject88k128kNoneLow
Daemons
ProgramBase MemoryMax MemoryTemp +FilesCPU Usage
cups-lpd92k256kOne file per control +or data file from clientLow
cupsd308kSee Scheduler Requirements +See Scheduler RequirementsMedium
cups-polld84kSize of printer and class objects +NoneLow
Filters
ProgramBase MemoryMax MemoryTemp +FilesCPU Usage
hpgltops263k320kNoneMedium
imagetops628k10MSwap file for +uncompressed image dataMedium
imagetoraster652k10MSwap file for +uncompressed image dataHigh
pstops775k840kUp to size of print +fileMedium
pstoraster4M14MSwap file for command +listsHigh
rastertoepson693k1MNoneLow
rastertohp690k1MNoneLow
texttops638k4*cols*rowsNone +Low
+
+

+

4 Scheduler Objects

+

The cupsd program is the CUPS scheduler process. It +manages many interdependent server objects that are used to manage and +print files to printers.

+

The following table provides the memory and disk cost associated +with each server object. +

+ + + + + + + + + + + + + + + +
ObjectMemory PerDisk Per
Browse ACL1k120
Browse Poll2480
Browse Relay2880
Certificate7632
Class9k200
Client13k-
Device256-
Job2k1k + size of document files
Location ACL1k120
MIME Filter26880
MIME Type34080
PPD200656
Printer11k32k
+
+

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/sps.pdf b/doc/sps.pdf new file mode 100644 index 0000000000000000000000000000000000000000..79527d3fb57b18eab62b0b6cd87413e48a65eeb6 GIT binary patch literal 33691 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�MDLnBUSSaS7kz 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 bK^^8W+t?DVZRf{0AT4n-^YhE8$us{Ccd|w& literal 0 Hc-jL100001 diff --git a/doc/sps.shtml b/doc/sps.shtml new file mode 100644 index 0000000000..92c8f71019 --- /dev/null +++ b/doc/sps.shtml @@ -0,0 +1,457 @@ + + + + + + CUPS Software Performance Specification + + + +

Scope

+ +

Identification

+ +

This software performance specification provides an analysis of the +memory, disk, and processor utilitization of each program in the +Common UNIX Printing System ("CUPS") Version 1.1.

+ +

For the purposes of comparison, all figures are for the Linux Intel +platform. Memory utilization on other platforms should be similar. + + + +

Document Overview

+ +

This software performance specification is organized into the +following sections:

+ +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Programs
  • +
  • 4 - Scheduler Objects
  • +
  • A - Glossary
  • +
+ + + +

Programs

+ +

The following table describes the average memory, disk, and CPU usage of +each program in CUPS. + +

The base memory column shows the initial memory requirements for each +program, including any shared libraries that are provided by CUPS. + +

The max memory column shows the maximum amount of memory that will be +used by the program based upon the default configuration settings supplied +with CUPS. + +

The temp files column indicates whether any temporary files are created. + +

The CPU usage column specifies a relative CPU usage by the program under +normal conditions, either low, medium, or high. Low usage indicates that +the program will never use more than 33% of the available CPU time. Medium +usage indicates the program will use as much as 66% of the available CPU +time. High usage indicates the program uses 66% or more of the available CPU +time. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Backends
ProgramBase MemoryMax MemoryTemp FilesCPU Usage
ipp91k256kUp to size of print fileLow
lpd89k89kUp to size of print fileLow
parallel85k85kUp to size of print fileLow
serial85k85kUp to size of print fileLow
socket85k85kUp to size of print fileLow
usb85k85kUp to size of print fileLow
CGIs
ProgramBase MemoryMax MemoryTemp FilesCPU Usage
admin.cgi107k256kUp to size of PPD fileMedium
classes.cgi95kSize of class objectsNoneMedium
jobs.cgi93kSize of job objectsNoneMedium
printers.cgi95kSize of printer objectsNoneMedium
Command-Line Programs
ProgramBase MemoryMax MemoryTemp FilesCPU Usage
accept88k128kNoneLow
cancel88k128kNoneLow
disable88k128kNoneLow
enable88k128kNoneLow
lp90k256kNoneLow
lpadmin148k256kNoneLow
lpc86kSize of job and printer objectsNoneMedium
lpinfo89kSize of device and PPD objectsNoneMedium
lpmove88k128kNoneLow
lpoptions89k128kNoneLow
lppasswd90k90kNoneLow
lpq87kSize of job objectsNoneMedium
lpr87k256kNoneLow
lprm84k128kNoneLow
lpstat119kSize of job, printer, and class objectsNoneMedium
reject88k128kNoneLow
Daemons
ProgramBase MemoryMax MemoryTemp FilesCPU Usage
cups-lpd92k256kOne file per control or data file from clientLow
cupsd308kSee Scheduler RequirementsSee Scheduler RequirementsMedium
cups-polld84kSize of printer and class objectsNoneLow
Filters
ProgramBase MemoryMax MemoryTemp FilesCPU Usage
hpgltops263k320kNoneMedium
imagetops628k10MSwap file for uncompressed image dataMedium
imagetoraster652k10MSwap file for uncompressed image dataHigh
pstops775k840kUp to size of print fileMedium
pstoraster4M14MSwap file for command listsHigh
rastertoepson693k1MNoneLow
rastertohp690k1MNoneLow
texttops638k4*cols*rowsNoneLow
+ + +

Scheduler Objects

+ +

The cupsd program is the CUPS scheduler process. It manages +many interdependent server objects that are used to manage and print files +to printers. + +

The following table provides the memory and disk cost associated with each +server object. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ObjectMemory PerDisk Per
Browse ACL1k120
Browse Poll2480
Browse Relay2880
Certificate7632
Class9k200
Client13k-
Device256-
Job2k1k + size of document files
Location ACL1k120
MIME Filter26880
MIME Type34080
PPD200656
Printer11k32k
+ + + + + diff --git a/doc/ssr.html b/doc/ssr.html new file mode 100644 index 0000000000..f06bfd2216 --- /dev/null +++ b/doc/ssr.html @@ -0,0 +1,270 @@ + + + + CUPS Software Security Report + + + + + + + +

+

CUPS Software Security Report


+CUPS-SSR-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Local Access Risks + +4 Remote Access Risks + +A Glossary + +
+

1 Scope

+

1.1 Identification

+

This software security report provides an analysis of possible +security concerns for the Common UNIX Printing System ("CUPS") Version +1.1.

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This software security report is organized into the following +sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Access Risks
  • +
  • 4 - Remote Access Risks
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Local Access Risks

+

Local access risks are those that can be exploited only with a local +user account. This section does not address issues related to +dissemination of the root password or other security issues associated +with the UNIX operating system.

+

3.1 Security Breaches

+

There is one known security vulnerability with local access:

+
    +
  1. Device URIs are passed to backend filters in argv[0] and in an +environment variable. Since device URIs can contain usernames and +passwords it may be possible for a local user to gain access to a +remote resource.
  2. +

    We recommend that any password-protected accounts used for remote +printing have limited access priviledges so that the possible damages +can be minimized.

    +

    The device URI is "sanitized" (the username and password are + removed) when sent to an IPP client so that a remote user cannot +exploit this vulnerability.

    +
+

4 Remote Access Risks

+

Remote access risks are those that can be exploited without a local +user account and/or from a remote system. This section does not address +issues related to network or firewall security.

+

4.1 Denial of Service Attacks

+

Like all Internet services, the CUPS server is vulnerable to denial +of service attacks, including:

+
    +
  1. Establishing multiple connections to the server until the server + will accept no more.
  2. +

    This cannot be protected against by the current software. It is +possible that future versions of the CUPS software could be configured +to limit the number of connections allowed from a single host, however +that still would not prevent a distributed attack.

    +
  3. Repeatedly opening and closing connections to the server as fast + as possible.
  4. +

    There is no easy way of protecting against this in the CUPS + software. If the attack is coming from outside the local network it +might be possible to filter such an attack, however once the +connection request has been received by the server it must at least +accept the connection to find out who is connecting.

    +
  5. Flooding the network with broadcast packets on port 631.
  6. +

    It might be possible to disable browsing if this condition is +detected by the CUPS software, however if there are large numbers of +printers available on the network such an algorithm might think that +an attack was occurring when instead a valid update was being +received.

    +
  7. Sending partial IPP requests; specifically, sending part of an + attribute value and then stopping transmission.
  8. +

    The current code is structured to read and write the IPP request +data on-the-fly, so there is no easy way to protect against this for +large attribute values.

    +
  9. Sending large/long print jobs to printers, preventing other users + from printing.
  10. +

    There are limited facilities for protecting against large print + jobs (the MaxRequestSize attribute), however this will + not protect printers from malicious users and print files that + generate hundreds or thousands of pages. In general, we recommend + restricting printer access to known hosts or networks, and adding + user-level access control as needed for expensive printers.

    +
+

4.2 Security Breaches

+

The current CUPS server supports Basic, Digest, and local +certificate authentication:

+
    +
  1. Basic authentication essentially places the clear text of the +username and password on the network. Since CUPS uses the UNIX +username and password account information, the authentication +information could be used to gain access to accounts (possibly +priviledged accounts) on the server.
  2. +
  3. Digest authentication uses an MD5 checksum of the username, + password, and domain ("CUPS"), so the original username and password +is not sent over the network. However, the current implementation does +not authenticate the entire message and uses the client's IP address +for the nonce value, making it possible to launch "man in the middle" +and replay attacks from the same client. The next minor release of +CUPS will support Digest authentication of the entire message body, +effectively stopping these methods of attack.
  4. +
  5. Local certificate authentication passes 128-bit "certificates" +that identify an authenticated user. Certificates are created +on-the-fly from random data and stored in files under +/etc/cups/certs. They have restricted read permissions: root + +system for the root certificate, and lp + system for CGI certificates. +Because certificates are only available on the local system, the CUPS + server does not accept local authentication unless the client is +connected to the localhost address (127.0.0.1.)
  6. +
+

The default CUPS configuration disables remote administration. We do +not recommend that remote administration be enabled for all hosts. +However, if you have a trusted network or subnet, access can be +restricted accordingly. Also, we highly recommend using Digest +authentication when possible. Unfortunately, most web browsers do not +support Digest authentication at this time.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/ssr.pdf b/doc/ssr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f24244cd93deca569d3e80431307c6010d454491 GIT binary patch literal 31595 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 Q2+f@RRdjV{JKL!I8!Il?+5i9m literal 0 Hc-jL100001 diff --git a/doc/ssr.shtml b/doc/ssr.shtml new file mode 100644 index 0000000000..472e44e6f5 --- /dev/null +++ b/doc/ssr.shtml @@ -0,0 +1,167 @@ + + + + + + CUPS Software Security Report + + + +

Scope

+ +

Identification

+ +

This software security report provides an analysis of possible security +concerns for the Common UNIX Printing System ("CUPS") Version 1.1.

+ + + +

Document Overview

+ +

This software security report is organized into the following sections:

+ +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Access Risks
  • +
  • 4 - Remote Access Risks
  • +
  • A - Glossary
  • +
+ + + +

Local Access Risks

+ +

Local access risks are those that can be exploited only with a local user +account. This section does not address issues related to dissemination of the +root password or other security issues associated with the UNIX operating +system. + +

Security Breaches

+ +

There is one known security vulnerability with local access: + +

    + +
  1. Device URIs are passed to backend filters in argv[0] and in + an environment variable. Since device URIs can contain + usernames and passwords it may be possible for a local user to + gain access to a remote resource. + +

    We recommend that any password-protected accounts used for + remote printing have limited access priviledges so that the + possible damages can be minimized. + +

    The device URI is "sanitized" (the username and password are + removed) when sent to an IPP client so that a remote user + cannot exploit this vulnerability. + +

+ +

Remote Access Risks

+ +

Remote access risks are those that can be exploited without a local user +account and/or from a remote system. This section does not address issues +related to network or firewall security. + +

Denial of Service Attacks

+ +

Like all Internet services, the CUPS server is vulnerable to denial of +service attacks, including: + +

    + +
  1. Establishing multiple connections to the server until the server + will accept no more. + +

    This cannot be protected against by the current software. It + is possible that future versions of the CUPS software could be + configured to limit the number of connections allowed from a + single host, however that still would not prevent a distributed + attack. + +

  2. Repeatedly opening and closing connections to the server as fast + as possible. + +

    There is no easy way of protecting against this in the CUPS + software. If the attack is coming from outside the local + network it might be possible to filter such an attack, however + once the connection request has been received by the server it + must at least accept the connection to find out who is + connecting. + +

  3. Flooding the network with broadcast packets on port 631. + +

    It might be possible to disable browsing if this condition + is detected by the CUPS software, however if there are large + numbers of printers available on the network such an algorithm + might think that an attack was occurring when instead a valid + update was being received. + +

  4. Sending partial IPP requests; specifically, sending part of an + attribute value and then stopping transmission. + +

    The current code is structured to read and write the IPP + request data on-the-fly, so there is no easy way to protect + against this for large attribute values. + +

  5. Sending large/long print jobs to printers, preventing other users + from printing. + +

    There are limited facilities for protecting against large print + jobs (the MaxRequestSize attribute), however this will + not protect printers from malicious users and print files that + generate hundreds or thousands of pages. In general, we recommend + restricting printer access to known hosts or networks, and adding + user-level access control as needed for expensive printers. + +

+ +

Security Breaches

+ +

The current CUPS server supports Basic, Digest, and local certificate +authentication: + +

    + +
  1. Basic authentication essentially places the clear text of + the username and password on the network. Since CUPS uses the + UNIX username and password account information, the + authentication information could be used to gain access to + accounts (possibly priviledged accounts) on the server. + +
  2. Digest authentication uses an MD5 checksum of the username, + password, and domain ("CUPS"), so the original username and + password is not sent over the network. However, the current + implementation does not authenticate the entire message and + uses the client's IP address for the nonce value, making it + possible to launch "man in the middle" and replay attacks from + the same client. The next minor release of CUPS will support + Digest authentication of the entire message body, effectively + stopping these methods of attack. + +
  3. Local certificate authentication passes 128-bit + "certificates" that identify an authenticated user. + Certificates are created on-the-fly from random data and stored + in files under /etc/cups/certs. They have + restricted read permissions: root + system for the root + certificate, and lp + system for CGI certificates. Because + certificates are only available on the local system, the CUPS + server does not accept local authentication unless the client + is connected to the localhost address (127.0.0.1.) + +
+ +

The default CUPS configuration disables remote administration. We do +not recommend that remote administration be enabled for all hosts. +However, if you have a trusted network or subnet, access can be +restricted accordingly. + +Also, we highly recommend using Digest authentication when possible. +Unfortunately, most web browsers do not support Digest authentication +at this time. + + + + + diff --git a/doc/stp.html b/doc/stp.html new file mode 100644 index 0000000000..2ed71e25a0 --- /dev/null +++ b/doc/stp.html @@ -0,0 +1,262 @@ + + + + CUPS Software Test Plan + + + + + + + +


+

CUPS Software Test Plan


+CUPS-STP-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Test Procedure +
+
4 IPP Compliance Tests + +5 Command Tests + +A Glossary + +
+

1 Scope

+

1.1 Identification

+

This software test plan provides detailed tests that are used to +evaluate the stability and compliance of the Common UNIX Printing +System ("CUPS") Version 1.1.

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This software test plan is organized into the following sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Test Procedure
  • +
  • 4 - IPP Compliance Tests
  • +
  • 5 - Command Tests
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Test Procedure

+

The test software and data files are located in the test + subdirectory of the source distribution. A script is provided to +compile the ipptest program and run all of the tests that +follow, producing a success/fail report.

+

The test target of the top-level makefile can be used +to run this script:

+
    +
    +make test
    +
    +
+

or you can run the test script directly:

+
    +
    +cd test
    +./run-stp-tests
    +
    +
+

A Software Test Report is stored in HTML and PDF files that are +generated using the HTMLDOC + software.

+

4 IPP Compliance Tests

+

This section describes the tests used to validate the IPP standards +compliance of the CUPS server.

+

4.1 Request Tests

+

These tests verify that the CUPS scheduler only accepts valid IPP +requests that start with the attributes-charset and +attributes-natural-language attributes and also contain a +printer-uri or job-uri attribute.

+

It also verifies that the CUPS scheduler always responds with +attributes-charset and attributes-natural-language + attributes, using default values if they are not provided by the +client.

+

4.2 CUPS Printer Operation Tests

+

These tests verify that the CUPS printer operations are supported +and function properly. Two printers called Test1 and +Test2 are created, one as a PostScript printer and one as a +raster printer.

+

4.3 Job Operation Tests

+

These test verify that the CUPS scheduler accepts print jobs for all +supported file formats and that the cancel-job, +hold-job, and resume-job operations work.

+

5 Command Tests

+

This section describes the tests used to validate the Berkeley and +System V commands included with CUPS.

+

5.1 lpadmin

+

This test verifies that printers can be added, modified, and +defaulted using the lpadmin command.

+

5.2 lpc

+

This test verifies that the lpc command can show the +current status of all print queues.

+

5.3 lpq

+

This test verifies that the lpq command lists any jobs +in the queue.

+

5.4 lpstat

+

This test verifies that the lpstat command works with +all reports using the "-t" option.

+

5.5 lp

+

This test verifies that the lp command works with both +the default destination and a specific destination.

+

5.6 lpr

+

This test verifies that the lpr command works with both +the default destination and a specific destination.

+

5.7 lprm

+

This test verifies that the lprm command can properly +cancel a job.

+

5.8 cancel

+

This test verifies that the cancel command can properly +cancel a job or all jobs.

+

5.9 lpinfo

+

This test verifies that the lpinfo command returns a +list of available printer drivers and devices.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/stp.pdf b/doc/stp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..00637189090c1b30795aa9f046c0e8eb7de0a6a0 GIT binary patch literal 35192 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 SeuR + + + + + + CUPS Software Test Plan + + + +

Scope

+ +

Identification

+ +

This software test plan provides detailed tests that are used +to evaluate the stability and compliance of the Common UNIX +Printing System ("CUPS") Version 1.1. + + + +

Document Overview

+ +

This software test plan is organized into the following sections: + +

    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Test Procedure
  • +
  • 4 - IPP Compliance Tests
  • +
  • 5 - Command Tests
  • +
  • A - Glossary
  • +
+ + + +

Test Procedure

+ +

The test software and data files are located in the test +subdirectory of the source distribution. A script is provided to compile +the ipptest program and run all of the tests that follow, +producing a success/fail report. + +

The test target of the top-level makefile can be used to +run this script: + +

    +make test
    +
+ +

or you can run the test script directly: + +

    +cd test
    +./run-stp-tests
    +
+ +

A Software Test Report is stored in HTML and PDF files that +are generated using the +HTMLDOC software. + +

IPP Compliance Tests

+ +

This section describes the tests used to validate the IPP +standards compliance of the CUPS server. + +

Request Tests

+ +

These tests verify that the CUPS scheduler only accepts valid +IPP requests that start with the attributes-charset +and attributes-natural-language attributes and also +contain a printer-uri or job-uri attribute. + +

It also verifies that the CUPS scheduler always responds with +attributes-charset and +attributes-natural-language attributes, using +default values if they are not provided by the client. + +

CUPS Printer Operation Tests

+ +

These tests verify that the CUPS printer operations are supported +and function properly. Two printers called Test1 and +Test2 are created, one as a PostScript printer and one +as a raster printer. + +

Job Operation Tests

+ +

These test verify that the CUPS scheduler accepts print jobs for +all supported file formats and that the cancel-job, +hold-job, and resume-job operations work. + +

Command Tests

+ +

This section describes the tests used to validate the +Berkeley and System V commands included with CUPS. + +

lpadmin

+ +

This test verifies that printers can be added, modified, and +defaulted using the lpadmin command. + +

lpc

+ +

This test verifies that the lpc command can show +the current status of all print queues. + +

lpq

+ +

This test verifies that the lpq command lists +any jobs in the queue. + +

lpstat

+ +

This test verifies that the lpstat command works +with all reports using the "-t" option. + +

lp

+ +

This test verifies that the lp command works +with both the default destination and a specific destination. + +

lpr

+ +

This test verifies that the lpr command works +with both the default destination and a specific destination. + +

lprm

+ +

This test verifies that the lprm command can +properly cancel a job. + +

cancel

+ +

This test verifies that the cancel command can +properly cancel a job or all jobs. + +

lpinfo

+ +

This test verifies that the lpinfo command +returns a list of available printer drivers and devices. + + + + + diff --git a/doc/sum.html b/doc/sum.html new file mode 100644 index 0000000000..576c6c8b05 --- /dev/null +++ b/doc/sum.html @@ -0,0 +1,1643 @@ + + + +CUPS Software Users Manual + + + + + + + +


+

CUPS Software Users Manual


+CUPS-SUM-1.1.7
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - Using the Printing System + +3 - Standard Printer Options + +4 - Saving Printer Options and Defaults + +A - Software License Agreement + +
+

Preface

+

This software users manual describes how to use the Common UNIX +Printing SystemTM ("CUPSTM") Version 1.1.7.

+

System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+ + +

Document Overview

+

This software users manual is organized into the following sections:

+ +

Notation Conventions

+

Various font and syntax conventions are used in this guide. Examples +and their meanings and uses are explained below: +

+ + + + + + + + + + + + +
Example   Description
 
lpstat +
lpstat(1)
   The names of commands; +the first mention of a command or function in a chapter is followed by +a manual page section number.
 
/var +
/usr/share/cups/data/testprint.ps
    +File and directory names.
 
Request ID is Printer-123 +   Screen output.
 
lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are +written using the period (.) to indicate the decimal point.
+
+ + +

+

Abbreviations

+ The following abbreviations are used throughout this manual: +
    +
    +
    kb
    +
    Kilobytes, or 1024 bytes +
     
    +
    Mb
    +
    Megabytes, or 1048576 bytes +
     
    +
    Gb
    +
    Gigabytes, or 1073741824 bytes +
     
    +
    +
+

Other References

+
    +
    +
    CUPS Software Administrators Manual
    +
    An administration guide for the CUPS software. +
     
    +
    CUPS Software Programmers Manual
    +
    A programmer guide for interfacing with and/or extending the CUPS + software. +
     
    +
    +
+

1 - Printing System Overview

+

This chapter provides an overview of how the Common UNIX Printing +System works.

+

The Printing Problem

+

For years the printing problem has plagued UNIX. Unlike +Microsoft® Windows® or Mac OS, UNIX has no standard interface or system +in place for supporting printers. Among the solutions currently +available, the Berkeley and System V printing systems are the most +prevalent.

+

These printing systems support line printers (text only) or +PostScript printers (text and graphics), and with some coaxing they can +be made to support a full range of printers and file formats. However, +because each varient of the UNIX operating system uses a different +printing system than the next developing printer drivers for a wide +range of printers and operating systems is extremely difficult. That +combined with the limited volume of customers for each UNIX varient has +forced most printer vendors to give up supporting UNIX entirely.

+

CUPS is designed to eliminate the printing problem. One +common printing system can be used by all UNIX varients to support the +printing needs of users. Printer vendors can use its modular filter +interface to develop a single driver program that supports a wide range +of file formats with little or no effort. Since CUPS provides both the +System V and Berkeley printing commands, users (and applications) can +reap the benefits of this new technology with no changes.

+

The Technology

+

CUPS is based upon an emerging Internet standard called the Internet +Printing Protocol. IPP has been embraced by dozens of printer and +printer server manufacturers and is supported by Microsoft Windows +2000.

+

IPP defines a standard protocol for printing as well as managing +print jobs and printer options like media size, resolution, and so +forth. Like all IP-based protocols, IPP can be used locally or over the +Internet to printers hundreds or thousands of miles away. Unlike other +protocols, however, IPP also supports access control, authentication, +and encryption, making it a much more capable and secure printing +solution than older ones.

+

IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") +which is the basis of web servers on the Internet. This allows users to +view documentation, check status information on a printer or server, +and manage their printers, classes, and jobs using their web browser.

+

CUPS provides a complete IPP/1.1 based printing system that provides +Basic, Digest, and local certificate authentication and user, domain, +or IP-based access control. TLS encryption will be available in future +versions of CUPS.

+

Jobs

+

Each file or set of files that is submitted for printing is called a +job. Jobs are identified by a unique number starting at 1 and are +assigned to a particular destination, usually a printer. Jobs can also +have options associated with them such as media size, number of copies, +and priority.

+

Classes

+

CUPS supports collections of printers known as classes. Jobs +sent to a class are forwarded to the first available printer in the +class.

+

Filters

+

Filters allow a user or application to print many types of files +without extra effort. Print jobs sent to a CUPS server are filtered +before sending them to a printer. Some filters convert job files to +different formats that the printer can understand. Others perform page +selection and ordering tasks.

+

CUPS provides filters for printing many types of image files, +HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript +and image file Raster Image Processor ("RIP") filters that convert +PostScript or image files into bitmaps that can be sent to a raster +printer.

+

Backends

+

Backends perform the most important task of all - they send the +filtered print data to the printer.

+

CUPS provides backends for printing over parallel, serial, and USB +ports, and over the network via the IPP, JetDirect (AppSocket), and +Line Printer Daemon ("LPD") protocols. Additional backends are +available in network service packages such as the SMB backend included +with the popular SAMBA software.

+

Backends are also used to determine the available devices. On +startup each backend is asked for a list of devices it supports, and +any information that is available. This allows the parallel backend to +tell CUPS that an EPSON Stylus Color 600 printer is attached to +parallel port 1, for example.

+

Printer Drivers

+

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes sample printer drivers for Hewlett-Packard +LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, +and Stylus Photo printers. While these drivers do not generate optimal +output for the different printer models, they do provide basic printing +and demonstrate how you can write your own printer drivers and +incorporate them into CUPS.

+

Networking

+

Printers and classes on the local system are automatically shared +with other systems on the network. This allows you to setup one system +to print to a printer and use this system as a printer server or spool +host for all of the others. Users may then select a local printer by +name or a remote printer using "name@server".

+

CUPS also provides implicit classes, which are collections of +printers and/or classes with the same name. This allows you to setup +multiple servers pointing to the same physical network printer, for +example, so that you aren't relying on a single system for printing. +Because this also works with printer classes, you can setup multiple +servers and printers and never worry about a single point of failure +unless all of the printers and servers go down!

+

2 - Using the Printing System +

+

This chapter shows you how to submit, query, and cancel print jobs +to different printers.

+

Submitting Files for Printing

+

CUPS provides both the System V (lp(1)) and Berkeley ( +lpr(1)) printing commands. Type the following command to print a +file to the default (or only) printer on the system:

+
    +
    +lp filename ENTER
    +
    +
+

or:

+
    +
    +lpr filename ENTER
    +
    +
+

CUPS understands many different types of files directly, including +PostScript and image files. This allows you to print from inside your +applications or at the command-line, whichever is most convenient!

+

Choosing a Printer

+

Many systems will have more than one printer available to the user. +These printers can be attached to the local system via a parallel, +serial, or USB port, or available over the network.

+

Use the lpstat(1) command to see a list of available +printers:

+
    +
    +lpstat -p -d ENTER
    +
    +
+

The -p option specifies that you want to see a list of +printers, and the -d option reports the current system +default printer or class.

+

Use the -d option with the lp command to +print to a specific printer:

+
    +
    +lp -d printer filename ENTER
    +
    +
+

or the -P option with the lpr command:

+
    +
    +lpr -P printer filename ENTER
    +
    +
+

Setting Printer Options

+

For many types of files, the default printer options may be +sufficient for your needs. However, there may be times when you need to +change the options for a particular file you are printing.

+

The lp and lpr commands allow you to pass +printer options using the -o option:

+
    +
    +lp -o landscape -o scaling=75 -o media=A4 filename.jpg
    +lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
    +
    +
+

The available printer options vary depending on the printer. The +standard options are described in Chapter +3, "Standard Printing Options".

+

Printing Multiple Copies

+

Both the lp and lpr commands have options +for printing more than one copy of a file:

+
    +
    +lp -n num-copies filename ENTER
    +lpr -#num-copies filename ENTER
    +
    +
+

Copies are normally not collated for you. Use the -o +Collate=True option to get collated copies :

+
    +
    +lp -n num-copies -o Collate=True filename ENTER
    +lpr -#num-copies -o Collate=True filename ENTER
    +
    +
+ + +

Checking the Printer Status from the Command-Line

+

The lpstat command can be used to check for jobs that +you have submitted for printing:

+
    +
    +lpstat ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +
    +
+

The jobs are listed in the order they will be printed. Use the +-p option to see which files and printers are active:

+
    +
    +lpstat -p ENTER
    +printer DeskJet now printing DeskJet-1.
    +
    +
+ + +

Use the -o and -p options together to show +the jobs and the printers:

+
    +
    +lpstat -o -p ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +printer DeskJet now printing DeskJet-1.
    +
    +
+

Checking the Printer Status from the Web

+

Since CUPS uses the Internet Printing Protocol, it is also a +fully-functional web server. To use your web browser to monitor the +printers on your system, open the URL:

+ +

From there you can view the status of classes, jobs, and printers +with the click of a button!

+

Canceling a Print Job

+

The cancel(1) and lprm(1) commands cancel +a print job:

+
    +
    +cancel job-id ENTER
    +lprm job-id ENTER
    +
    +
+

The job-id is the number that was reported to you by +the lp or lpstat commands.

+

3 - Standard Printer +Options

+

This chapter describes the standard printer options that are +available when printing with the lp and lpr + commands.

+

General Options

+

The following options apply when printing all types of files.

+

Setting the Orientation

+

The -o landscape option will rotate the page 90 degrees +to print in landscape orientation:

+
    +
    +lp -o landscape filename ENTER
    +lpr -o landscape filename ENTER
    +
    +
+ + +

Selecting the Media Size, Type, and Source

+

The -o media=xyz option sets the media size, type, +and/or source:

+
    +
    +lp -o media=Letter filename ENTER
    +lp -o media=Letter,MultiPurpose filename ENTER
    +lpr -o media=Letter,Transparency filename ENTER
    +lpr -o media=Letter,MultiPurpose,Transparency filename ENTER
    +
    +
+ + +

The available media sizes, types, and sources depend on the printer, +but most support the following options (case is not significant):

+
    +
  • Letter - US Letter (8.5x11 inches, or 216x279mm)
  • +
  • Legal - US Legal (8.5x14 inches, or 216x356mm)
  • +
  • A4 - ISO A4 (8.27x11.69 inches, or 210x297mm)
  • +
  • COM10 - US #10 Envelope (9.5x4.125 inches, or + 241x105mm)
  • +
  • DL - ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
  • +
  • Transparency - Transparency media type or source
  • +
  • Upper - Upper paper tray
  • +
  • Lower - Lower paper tray
  • +
  • MultiPurpose - Multi-purpose paper tray
  • +
  • LargeCapacity - Large capacity paper tray
  • +
+

The actual options supported are defined in the printer's PPD file +in the PageSize, InputSlot, and +MediaType options.

+

Printing On Both Sides of the Paper

+

The -o sides=two-sided-short-edge and -o +sides=two-sided-long-edge options will enable duplexing on the +printer, if the printer supports it. The -o +sides=two-sided-short-edge option is suitable for landscape +pages, while the -o sides=two-sided-long-edge option is +suitable for portrait pages:

+
    +
    +lp -o sides=two-sided-short-edge filename ENTER
    +lp -o sides=two-sided-long-edge filename ENTER
    +lpr -o sides=two-sided-long-edge filename ENTER
    +
    +
+

The default is to print single-sided:

+
    +
    +lp -o sides=one-sided filename ENTER
    +lpr -o sides=one-sided filename ENTER
    +
    +
+

Banner Options

+

The following options apply when printing all types of files.

+

Selecting the Banner Page(s)

+

The -o jobsheets=start,end option sets the banner +page(s) to use for a job:

+
    +
    +lp -o job-sheets=none filename ENTER
    +lp -o job-sheets=standard filename ENTER
    +lpr -o job-sheets=classified,classified filename ENTER
    +
    +
+

If only one banner file is specified, it will be printed before the +files in the job. If a second banner file is specified, it is printed +after the files in the job.

+

The available banner pages depend on the local system configuration; +CUPS includes the following banner files:

+
    +
  • none - Do not produce a banner page.
  • +
  • classified - A banner page with a "classified" label +at the top and bottom.
  • +
  • confidential - A banner page with a "confidential" +label at the top and bottom.
  • +
  • secret - A banner page with a "secret" label at the +top and bottom.
  • +
  • standard - A banner page with no label at the top and +bottom.
  • +
  • topsecret - A banner page with a "top secret" label +at the top and bottom.
  • +
  • unclassified - A banner page with an "unclassified" +label at the top and bottom.
  • +
+

Document Options

+

The following options apply when printing all types of files.

+

Selecting a Range of Pages

+

The -o page-ranges=pages option selects a range of +pages for printing:

+
    +
    +lp -o page-ranges=1 filename ENTER
    +lp -o page-ranges=1-4 filename ENTER
    +lp -o page-ranges=1-4,7,9-12 filename ENTER
    +lpr -o page-ranges=1-4,7,9-12 filename ENTER
    +
    +
+

As shown above, the pages value can be a single page, a +range of pages, or a collection of page numbers and ranges separated by +commas. The pages will always be printed in ascending order, regardless +of the order of the pages in the page-ranges option.

+

The default is to print all pages.

+

Selecting Even or Odd Pages

+

Use the -o page-set=set option to select the even or +odd pages:

+
    +
    +lp -o page-set=odd filename ENTER
    +lp -o page-set=even filename ENTER
    +lpr -o page-set=even filename ENTER
    +
    +
+

The default is to print all pages.

+

N-Up Printing

+

The -o number-up=value option selects N-Up printing. + N-Up printing places multiple document pages on a single printed page. + CUPS supports 1-Up, 2-Up, and 4-Up formats:

+
    +
    +lp -o number-up=1 filename ENTER
    +lp -o number-up=2 filename ENTER
    +lp -o number-up=4 filename ENTER
    +lpr -o number-up=4 filename ENTER
    +
    +
+

The default format is 1-Up.

+

Setting the Brightness

+

You can control the overall brightness of the printed output using +the -o brightness=percent option:

+
    +
    +lp -o brightness=120 filename ENTER
    +lpr -o brightness=120 filename ENTER
    +
    +
+

Values greater than 100 will lighten the print, while values less +than 100 will darken it.

+

Setting the Gamma Correction

+

You can control the overall gamma correction of the printed output +using the -o gamma=value option:

+
    +
    +lp -o gamma=1700 filename ENTER
    +lpr -o gamma=1700 filename ENTER
    +
    +
+

Values greater than 1000 will lighten the print, while values less +than 1000 will darken it. The default gamma is 1000.

+

Text Options

+

The following options apply when printing text files.

+

Setting the Number of Characters Per Inch

+

The -o cpi=value option sets the number of characters +per inch:

+
    +
    +lp -o cpi=10 filename ENTER
    +lp -o cpi=12 filename ENTER
    +lpr -o cpi=17 filename ENTER
    +
    +
+

The default characters per inch is 10.

+

Setting the Number of Lines Per Inch

+

The -o lpi=value option sets the number of lines per +inch:

+
    +
    +lp -o lpi=6 filename ENTER
    +lpr -o lpi=8 filename ENTER
    +
    +
+

The default lines per inch is 6.

+

Setting the Number of Columns

+

The -o columns=value option sets the number of text +columns:

+
    +
    +lp -o columns=2 filename ENTER
    +lpr -o columns=3 filename ENTER
    +
    +
+

The default number of columns is 1.

+

Setting the Page Margins

+

Normally the page margins are set to the hard limits of the printer. +Use the -o page-left=value, -o page-right=value +, -o page-top=value, and -o page-bottom=value + options to adjust the page margins:

+
    +
    +lp -o page-left=value filename ENTER
    +lp -o page-right=value filename ENTER
    +lp -o page-top=value filename ENTER
    +lp -o page-bottom=value filename ENTER
    +lpr -o page-bottom=value filename ENTER
    +
    +
+

The value argument is the margin in points; each point +is 1/72 inch or 0.35mm.

+

Pretty Printing

+

The -o prettyprint option puts a header at the top of +each page with the page number, job title (usually the filename), and +the date. Also, C and C++ keywords are highlighted, and comment lines +are italicized:

+
    +
    +lp -o prettyprint filename ENTER
    +lpr -o prettyprint filename ENTER
    +
    +
+

Image Options

+

The following options apply when printing image files.

+

Positioning the Image

+

The -o position=name option specifies the position of +the image on the page:

+
    +
  • center - Center the image on the page (default)
  • +
  • top - Print the image centered at the top of the page
  • +
  • left - Print the image centered on the left of page
  • +
  • right - Print the image centered on the right of the +page
  • +
  • top-left - Print the image at the top left corner of + the page
  • +
  • top-right - Print the image at the top right corner of + the page
  • +
  • bottom - Print the image centered at the bottom of + the page
  • +
  • bottom-left - Print the image at the bottom left + corner of the page
  • +
  • bottom-right - Print the image at the bottom right + corner of the page
  • +
+

Scaling the Image

+

The -o scaling=percent and -o ppi=value + options change the size of a printed image:

+
    +
    +lp -o scaling=percent filename ENTER
    +lp -o ppi=value filename ENTER
    +lpr -o ppi=value filename ENTER
    +
    +
+

The percent value is a number from 1 to 800 specifying +the size in relation to the page (not the image.) A scaling of +100 percent will fill the page as completely as the image aspect ratio +allows. A scaling of 200 percent will print on up to 4 pages.

+

The ppi value is a number from 1 to 1200 specifying the +resolution of the image in pixels per inch. An image that is 3000x2400 +pixels will print 10x8 inches at 300 pixels per inch, for example. If +the specified resolution makes the image larger than the page, multiple +pages will be printed to satisfy the request.

+

Adjusting the Hue (Tint) of an Image

+

The -o hue=value option will adjust the hue of the +printed image, much like the tint control on your television:

+
    +
    +lp -o hue=value filename ENTER
    +lpr -o hue=value filename ENTER
    +
    +
+ + +

The value argument is a number from -360 to 360 and +represents the color hue rotation. The following table summarizes the +change you'll see with different colors: +

+ + + + + + + + +
Originalhue=-45hue=45
RedPurpleYellow-orange
GreenYellow-greenBlue-green
YellowOrangeGreen-yellow
BlueSky-bluePurple
MagentaIndigoCrimson
CyanBlue-greenLight-navy-blue
+
+

+

The default hue adjustment is 0.

+

Adjusting the Saturation (Color) of an Image

+

The -o saturation=percent option adjusts the saturation +of the colors in an image, much like the color knob on your television:

+
    +
    +lp -o saturation=percent filename ENTER
    +lpr -o saturation=percent filename ENTER
    +
    +
+

The percent argument specifies the color saturation +from 0 to 200. A color saturation of 0 produces a black-and-white +print, while a value of 200 will make the colors extremely intense.

+

The default saturation is 100. + +

+

HP-GL/2 Options

+

The following options apply to HP-GL/2 files.

+

Printing in Black

+

The -o blackplot option specifies that all pens should +plot in black:

+
    +
    +lp -o blackplot filename ENTER
    +lpr -o blackplot filename ENTER
    +
    +
+

The default is to use the colors defined in the plot file or the +standard pen colors defined in the HP-GL/2 reference manual from +Hewlett Packard.

+

Fitting the Plot on the Page

+

The -o fitplot option specifies that the plot should be +scaled to fit on the page:

+
    +
    +lp -o fitplot filename ENTER
    +lpr -o fitplot filename ENTER
    +
    +
+

The default is to use the absolute distances specified in the plot +file. +

+ + +
NOTE: +

This feature depends upon an accurate plot size (PS) + command in the HP-GL/2 file. If no plot size is given in the file + than the HP-GL/2 filter assumes the plot is ANSI E size.

+
+
+

+

Setting the Default Pen Width

+

The -o penwidth=value option specifies the default pen +width for HP-GL/2 files:

+
    +
    +lp -o penwidth=value filename ENTER
    +lpr -o penwidth=value filename ENTER
    +
    +
+

The pen width value specifies the pen width in +micrometers. The default value of 1000 produces lines that are 1 +millimeter in width. Specifying a pen width of 0 produces lines that +are exactly 1 pixel wide. +

+ + +
NOTE: +

This option is ignored when the pen widths are set in the plot +file.

+
+
+

+

Raw or Unfiltered Output

+

The -o raw option allows you to send files directly to +a printer without filtering. This is sometimes required when printing +from applications that provide their own "printer drivers" for your +printer:

+
    +
    +lp -o raw filename ENTER
    +lpr -o raw filename ENTER
    +
    +
+

The -l option can also be used with the lpr + command to send files directly to a printer:

+
    +
    +lpr -l filename ENTER
    +
    +
+

4 - Saving Printer Options +and Defaults

+

This chapter describes how to save printer options for your printer +and set your own default printer.

+

Printer Options

+

Each printer supports a large number of options, which you learned +about in Chapter 3, "Standard Printer +Options". Rather than specifying these options each time you print +a file, CUPS allows you to save them as "default" options for the +printer.

+

The lpoptions(1) command saves the options for your +printers. Like the lp and lpr commands, it +accepts printer options using the -o argument:

+
    +
    +lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER
    +lpoptions -o media=Legal -o scaling=100 ENTER
    +
    +
+

Once saved, any lp or lpr command will use +them when you print.

+

Setting Options for a Specific Printer

+

The previous example shows how to set the options for the default +printer. The -p printer option specifies the options are +for another printer:

+
    +
    +lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER
    +lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER
    +
    +
+

Viewing the Current Defaults

+

The lpoptions command can also be used to show the +current options by not specifying any new options on the command-line:

+
    +
    +lpoptions ENTER
    +media=A4 sides=two-sided-long-edge
    +lpoptions -p deskjet ENTER
    +media=Legal scaling=100
    +
    +
+

Setting the Default Printer

+

The administrator normally will set a system-wide default printer +that is normally used as the default printer by everyone. Use the +-d printer option to set your own default printer:

+
    +
    +lpoptions -d deskjet ENTER
    +
    +
+

The printer can be local (deskjet) or remote ( +deskjet@server).

+

Printer Instances

+

Besides setting options for each print queue, CUPS supports +printer instances which allow you to define several different sets +of options for each printer. You specify a printer instance using the +slash (/) character:

+
    +
    +lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER
    +lpoptions -p laserjet/legal -o media=Legal ENTER
    +
    +
+

The lp and lpr commands also understand this notation:

+
    +
    +lp -d laserjet/duplex filename ENTER
    +lpr -P laserjet/legal filename ENTER
    +
    +
+

Removing Instances

+

Use the -x printer/instance option to remove a printer +instance that you no longer need:

+
    +
    +lpoptions -x laserjet ENTER
    +lpoptions -x laserjet/duplex ENTER
    +lpoptions -x laserjet/legal ENTER
    +
    +
+

The -x option only removes the default options for that +printer and instance; the original print queue will remain until +deleted with the lpadmin(8) command by the administrator.

+

A - Software License Agreement

+

Common UNIX Printing System License +Agreement

+

Copyright 1997-2001 by Easy Software Products +
44141 AIRPORT VIEW DR STE 204 +
HOLLYWOOD, MARYLAND 20636-3111 USA +
+
Voice: +1.301.373.9600 +
Email: cups-info@cups.org +
WWW: http://www.cups.org

+

Introduction

+

The Common UNIX Printing SystemTM, ("CUPSTM"), +is provided under the GNU General Public License ("GPL") and GNU +Library General Public License ("LGPL"), Version 2. A copy of these +licenses follow this introduction.

+

The GNU LGPL applies to the CUPS API library, located in the "cups" +subdirectory of the CUPS source distribution and in the +"/usr/include/cups" directory and "libcups.a", "libcups.sl", or +"libcups.so" files in the binary distributions.

+

The GNU GPL applies to the remainder of the CUPS distribution, +including the "pstoraster" filter which is based upon GNU Ghostscript +5.50 and the "pdftops" filter which is based upon Xpdf 0.90.

+

For those not familiar with the GNU GPL, the license basically +allows you to:

+
    +
  • Use the CUPS software at no charge.
  • +
  • Distribute verbatim copies of the software in source or binary +form.
  • +
  • Sell verbatim copies of the software for a media fee, or sell +support for the software.
  • +
  • Distribute or sell printer drivers and filters that use CUPS so +long as source code is made available under the GPL.
  • +
+

What this license does not allow you to do is make changes or +add features to CUPS and then sell a binary distribution without source +code. You must provide source for any new drivers, changes, or +additions to the software, and all code must be provided under the GPL +or LGPL as appropriate.

+

The GNU LGPL relaxes the "link-to" restriction, allowing you to +develop applications that use the CUPS API library under other licenses +and/or conditions as appropriate for your application.

+

Trademarks

+

Easy Software Products has trademarked the Common UNIX Printing +System, CUPS, and CUPS logo. These names and logos may be used freely +in any direct port or binary distribution of CUPS. To use them in +derivative products, please contract Easy Software Products for written +permission. Our intention is to protect the value of these trademarks +and ensure that any derivative product meets the same high-quality +standards as the original.

+

Binary Distribution Rights

+

Easy Software Products also sells rights to the CUPS source code +under a binary distribution license for vendors that are unable to +release source code for their drivers, additions, and modifications to +CUPS under the GNU GPL and LGPL. For information please contact us at +the address shown above.

+

The Common UNIX Printing System provides a "pstoraster" filter that +utilizes the GNU GhostScript 5.50 core to convert PostScript files into +a stream of raster images. For binary distribution licensing of this +software, please contact:

Miles Jones +
Director of Marketing +
Artifex Software Inc. +
454 Las Gallinas Ave., Suite 108 +
San Rafael, CA 94903 USA +
Voice: +1.415.492.9861 +
Fax: +1.415.492.9862 +
EMail: info@arsoft.com
+

+

The "pdftops" filter is based on the Xpdf 0.90 software. For binary +distribution licensing of this software, please contact:

+ Derek B. Noonburg +
Email: derekn@foolabs.com +
WWW: +http://www.foolabs.com/xpdf/

+

Support

+

Easy Software Products sells software support for CUPS as well as a +commercial printing product based on CUPS called ESP Print Pro. You can +find out more at our web site:

+ + + +

GNU GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not allowed.
+
+
+
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it.

+

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights.

+

We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the software.

+

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, +so that any problems introduced by others will not reflect on the +original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all.

+

The precise terms and conditions for copying, distribution and +modification follow.

+

GNU GENERAL PUBLIC LICENSE +
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+
    +
  1. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you".
  2. +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does.

    +
  3. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the +Program.
  4. +

    You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

    +
  5. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: +
      +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change.
    2. +
    3. You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License.
    4. +
    5. if the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the most ordinary way, to print or display an announcement including +an appropriate copyright notice and a notice that there is no warranty +(or else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling the user +how to view a copy of this License. (Exception: if the Program itself +is interactive but does not normally print such an announcement, your +work based on the Program is not required to print an announcement.)
    6. +
    +
  6. +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

    +

    Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Program.

    +

    In addition, mere aggregation of another work not based on the +Program with the Program (or with a work based on the Program) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

    +
  7. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +
      +
    1. Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or,
    2. +
    3. Accompany it with a written offer, valid for at least three years, +to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or,
    4. +
    5. Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in accord +with Subsection b above.)
    6. +
    +
  8. +

    The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that +is normally distributed (in either source or binary form) with the +major components (compiler, kernel, and so on) of the operating system +on which the executable runs, unless that component itself accompanies +the executable.

    +

    If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent access +to copy the source code from the same place counts as distribution of +the source code, even though third parties are not compelled to copy +the source along with the object code.

    +
  9. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such parties +remain in full compliance.
  10. +
  11. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying the +Program or works based on it.
  12. +
  13. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License.
  14. +
  15. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program.
  16. +

    If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply and the section as a whole is intended to apply in +other circumstances.

    +

    It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.

    +

    This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

    +
  17. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License.
  18. +
  19. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns.
  20. +

    Each version is given a distinguishing version number. If the +Program specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation.

    +
  21. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally.
  22. +
+

NO WARRANTY

+
    +
  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS +WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  2. +
  3. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.
  4. +
+

END OF TERMS AND CONDITIONS

+ + +

GNU LIBRARY GENERAL PUBLIC LICENSE

+

Version 2, June 1991

+
+Copyright (C) 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+

Preamble

+

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users.

+

This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too.

+

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things.

+

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it.

+

For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights.

+

Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library.

+

Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations.

+

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all.

+

Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License, which was designed for utility +programs. This license, the GNU Library General Public License, +applies to certain designated libraries. This license is quite +different from the ordinary one; be sure to read it in full, and don't +assume that anything in it is the same as in the ordinary license.

+

The reason we have a separate public license for some libraries is +that they blur the distinction we usually make between modifying or +adding to a program and simply using it. Linking a program with a +library, without changing the library, is in some sense simply using +the library, and is analogous to running a utility program or +application program. However, in a textual and legal sense, the linked +executable is a combined work, a derivative of the original library, +and the ordinary General Public License treats it as such.

+

Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better.

+

However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended +to permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to +achieve this as regards changes in header files, but we have achieved +it as regards changes in the actual functions of the Library.) The +hope is that this will lead to faster development of free libraries.

+

The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library.

+

Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one.

+

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

0. This License Agreement applies to any software +library which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Library General Public License (also called "this License"). Each +licensee is addressed as "you".

+

A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables.

+

The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".)

+

"Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library.

+

Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does and +what the program that uses the Library does.

+

1. You may copy and distribute verbatim copies of +the Library's complete source code as you receive it, in any medium, +provided that you conspicuously and appropriately publish on each copy +an appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the Library.

+

You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.

+

2. You may modify your copy or copies of the +Library or any portion of it, thus forming a work based on the Library, +and copy and distribute such modifications or work under the terms of +Section 1 above, provided that you also meet all of these conditions:

+
    +
  1. The modified work must itself be a software library.
  2. +

    +
  3. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change.
  4. +

    +
  5. You must cause the whole of the work to be licensed at no charge +to all third parties under the terms of this License.
  6. +

    +
  7. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses the +facility, other than as an argument passed when the facility is +invoked, then you must make a good faith effort to ensure that, in the +event an application does not supply such function or table, the +facility still operates, and performs whatever part of its purpose +remains meaningful.
  8. +

    (For example, a function in a library to compute square roots has a +purpose that is entirely well-defined independent of the application. + Therefore, Subsection 2d requires that any application-supplied +function or table used by this function must be optional: if the +application does not supply it, the square root function must still +compute square roots.)

    +
+

These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.

+

Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Library.

+

In addition, mere aggregation of another work not based on the +Library with the Library (or with a work based on the Library) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License.

+

3. You may opt to apply the terms of the ordinary +GNU General Public License instead of this License to a given copy of +the Library. To do this, you must alter all the notices that refer to +this License, so that they refer to the ordinary GNU General Public +License, version 2, instead of to this License. (If a newer version +than version 2 of the ordinary GNU General Public License has appeared, +then you can specify that version instead if you wish.) Do not make +any other change in these notices.

+

Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy.

+

This option is useful when you wish to copy part of the code of the +Library into a program that is not a library.

+

4. You may copy and distribute the Library (or a +portion or derivative of it, under Section 2) in object code or +executable form under the terms of Sections 1 and 2 above provided that +you accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange.

+

If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to distribute +the source code, even though third parties are not compelled to copy +the source along with the object code.

+

5. A program that contains no derivative of any +portion of the Library, but is designed to work with the Library by +being compiled or linked with it, is called a "work that uses the +Library". Such a work, in isolation, is not a derivative work of the +Library, and therefore falls outside the scope of this License.

+

However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. Section +6 states terms for distribution of such executables.

+

When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law.

+

If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.)

+

Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, whether +or not they are linked directly with the Library itself.

+

6. As an exception to the Sections above, you may +also compile or link a "work that uses the Library" with the Library to +produce a work containing portions of the Library, and distribute that +work under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications.

+

You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things:

+
    +
  1. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that uses +the Library", as object code and/or source code, so that the user can +modify the Library and then relink to produce a modified executable +containing the modified Library. (It is understood that the user who +changes the contents of definitions files in the Library will not +necessarily be able to recompile the application to use the modified +definitions.)
  2. +

    +
  3. Accompany the work with a written offer, valid for at least three +years, to give the same user the materials specified in Subsection 6a, +above, for a charge no more than the cost of performing this +distribution.
  4. +

    +
  5. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place.
  6. +

    +
  7. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy.
  8. +
+

For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major components +(compiler, kernel, and so on) of the operating system on which the +executable runs, unless that component itself accompanies the +executable.

+

It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute.

+

7. You may place library facilities that are a work +based on the Library side-by-side in a single library together with +other library facilities not covered by this License, and distribute +such a combined library, provided that the separate distribution of the +work based on the Library and of the other library facilities is +otherwise permitted, and provided that you do these two things:

+
    +
  1. Accompany the combined library with a copy of the same work based +on the Library, uncombined with any other library facilities. This +must be distributed under the terms of the Sections above.
  2. +

    +
  3. Give prominent notice with the combined library of the fact that +part of it is a work based on the Library, and explaining where to +find the accompanying uncombined form of the same work.
  4. +
+

8. You may not copy, modify, sublicense, link with, +or distribute the Library except as expressly provided under this +License. Any attempt otherwise to copy, modify, sublicense, link with, +or distribute the Library is void, and will automatically terminate +your rights under this License. However, parties who have received +copies, or rights, from you under this License will not have their +licenses terminated so long as such parties remain in full compliance.

+

9. You are not required to accept this License, +since you have not signed it. However, nothing else grants you +permission to modify or distribute the Library or its derivative works. + These actions are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Library (or any work based +on the Library), you indicate your acceptance of this License to do so, +and all its terms and conditions for copying, distributing or modifying +the Library or works based on it.

+

10. Each time you redistribute the Library (or any +work based on the Library), the recipient automatically receives a +license from the original licensor to copy, distribute, link with or +modify the Library subject to these terms and conditions. You may not +impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance +by third parties to this License.

+

11. If, as a consequence of a court judgment or +allegation of patent infringement or for any other reason (not limited +to patent issues), conditions are imposed on you (whether by court +order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. + If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Library at all. For +example, if a patent license would not permit royalty-free +redistribution of the Library by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Library.

+

If any portion of this section is held invalid or unenforceable +under any particular circumstance, the balance of the section is +intended to apply, and the section as a whole is intended to apply in +other circumstances.

+

It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up +to the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice.

+

This section is intended to make thoroughly clear what is believed +to be a consequence of the rest of this License.

+

12. If the distribution and/or use of the Library +is restricted in certain countries either by patents or by copyrighted +interfaces, the original copyright holder who places the Library under +this License may add an explicit geographical distribution limitation +excluding those countries, so that distribution is permitted only in or +among countries not thus excluded. In such case, this License +incorporates the limitation as if written in the body of this License.

+

13. The Free Software Foundation may publish +revised and/or new versions of the Library General Public License from +time to time. Such new versions will be similar in spirit to the +present version, but may differ in detail to address new problems or +concerns.

+

Each version is given a distinguishing version number. If the +Library specifies a version number of this License which applies to it +and "any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation.

+

14. If you wish to incorporate parts of the Library +into other free programs whose distribution conditions are incompatible +with these, write to the author to ask for permission. For software +which is copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally.

+

NO WARRANTY

+

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, +THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW +OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY +WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL +OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES.

+

END OF TERMS AND CONDITIONS

+ + diff --git a/doc/sum.pdf b/doc/sum.pdf new file mode 100644 index 0000000000000000000000000000000000000000..34bdc62d904101182b974b7c8d6c993d6ab613b3 GIT binary patch literal 95992 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 literal 0 Hc-jL100001 diff --git a/doc/sum.shtml b/doc/sum.shtml new file mode 100644 index 0000000000..46e689c3a0 --- /dev/null +++ b/doc/sum.shtml @@ -0,0 +1,878 @@ + + + + + + + CUPS Software Users Manual + + + +

Preface

+ +

This software users manual describes how to use the Common UNIX Printing +SystemTM ("CUPSTM") Version 1.1.7. + + + + +

Document Overview

+ +

This software users manual is organized into the following sections:

+ +
+ +

Notation Conventions

+ +

Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Example   Description
 
lpstat
+ lpstat(1)
   The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
 
/var
+ /usr/share/cups/data/testprint.ps
   File and directory names.
 
Request ID is Printer-123   Screen output.
 
lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
 
12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
+ + +

Abbreviations

+ +The following abbreviations are used throughout this manual: + +
    +
    + +
    kb +
    Kilobytes, or 1024 bytes
      + +
    Mb +
    Megabytes, or 1048576 bytes
      + +
    Gb +
    Gigabytes, or 1073741824 bytes
      + +
    +
+ +

Other References

+ +
    +
    + +
    CUPS Software Administrators Manual + +
    An administration guide for the CUPS software.
      + +
    CUPS Software Programmers Manual + +
    A programmer guide for interfacing with and/or extending the CUPS + software.
      + +
    +
+ + + + + +

2 - Using the Printing System

+ +

This chapter shows you how to submit, query, and cancel print jobs to +different printers. + +

Submitting Files for Printing

+ +

CUPS provides both the System V (lp(1)) and Berkeley +(lpr(1)) printing commands. Type the following command to +print a file to the default (or only) printer on the system: + +

    +lp filename ENTER
    +
+ +

or: + +

    +lpr filename ENTER
    +
+ +

CUPS understands many different types of files directly, including +PostScript and image files. This allows you to print from inside your +applications or at the command-line, whichever is most convenient! + +

Choosing a Printer

+ +

Many systems will have more than one printer available to the user. These +printers can be attached to the local system via a parallel, serial, or USB +port, or available over the network. + +

Use the lpstat(1) command to see a list of available printers: + +

    +lpstat -p -d ENTER
    +
+ +

The -p option specifies that you want to see a list of +printers, and the -d option reports the current system +default printer or class. + +

Use the -d option with the lp command to +print to a specific printer: + +

    +lp -d printer filename ENTER
    +
+ +

or the -P option with the lpr command: + +

    +lpr -P printer filename ENTER
    +
+ +

Setting Printer Options

+ +

For many types of files, the default printer options may be sufficient for +your needs. However, there may be times when you need to change the options +for a particular file you are printing. + +

The lp and lpr commands allow you to pass +printer options using the -o option: + +

    +lp -o landscape -o scaling=75 -o media=A4 filename.jpg
    +lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
    +
+ +

The available printer options vary depending on the printer. The standard +options are described in Chapter 3, "Standard +Printing Options". + +

Printing Multiple Copies

+ +

Both the lp and lpr commands have options for +printing more than one copy of a file: + +

    +lp -n num-copies filename ENTER
    +lpr -#num-copies filename ENTER
    +
+ +

Copies are normally not collated for you. Use the -o +Collate=True option to get collated copies : + +

    +lp -n num-copies -o Collate=True filename ENTER
    +lpr -#num-copies -o Collate=True filename ENTER
    +
+ + +

Checking the Printer Status from the Command-Line

+ +

The lpstat command can be used to check for jobs that you +have submitted for printing: + +

    +lpstat ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +
+ +

The jobs are listed in the order they will be printed. Use the +-p option to see which files and printers are active: + +

    +lpstat -p ENTER
    +printer DeskJet now printing DeskJet-1.
    +
+ + +

Use the -o and -p options together to show +the jobs and the printers: + +

    +lpstat -o -p ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +printer DeskJet now printing DeskJet-1.
    +
+ +

Checking the Printer Status from the Web

+ +

Since CUPS uses the Internet Printing Protocol, it is also a +fully-functional web server. To use your web browser to monitor the +printers on your system, open the URL: + +

+ +

From there you can view the status of classes, jobs, and printers +with the click of a button! + +

Canceling a Print Job

+ +

The cancel(1) and lprm(1) commands cancel +a print job: + +

    +cancel job-id ENTER
    +lprm job-id ENTER
    +
+ +

The job-id is the number that was reported to you by +the lp or lpstat commands. + + +

3 - Standard Printer Options

+ +

This chapter describes the standard printer options that are available +when printing with the lp and lpr commands. + +

General Options

+ +

The following options apply when printing all types of files. + +

Setting the Orientation

+ +

The -o landscape option will rotate the page 90 degrees +to print in landscape orientation: + +

    +lp -o landscape filename ENTER
    +lpr -o landscape filename ENTER
    +
+ + +

Selecting the Media Size, Type, and Source

+ +

The -o media=xyz option sets the media size, type, +and/or source: + +

    +lp -o media=Letter filename ENTER
    +lp -o media=Letter,MultiPurpose filename ENTER
    +lpr -o media=Letter,Transparency filename ENTER
    +lpr -o media=Letter,MultiPurpose,Transparency filename ENTER
    +
+ + +

The available media sizes, types, and sources depend on the printer, but +most support the following options (case is not significant): + +

    + +
  • Letter - US Letter (8.5x11 inches, or 216x279mm) + +
  • Legal - US Legal (8.5x14 inches, or 216x356mm) + +
  • A4 - ISO A4 (8.27x11.69 inches, or 210x297mm) + +
  • COM10 - US #10 Envelope (9.5x4.125 inches, or + 241x105mm) + +
  • DL - ISO DL Envelope (8.66x4.33 inches, or 220x110mm) + +
  • Transparency - Transparency media type or source + +
  • Upper - Upper paper tray + +
  • Lower - Lower paper tray + +
  • MultiPurpose - Multi-purpose paper tray + +
  • LargeCapacity - Large capacity paper tray + +
+ +

The actual options supported are defined in the printer's PPD file +in the PageSize, InputSlot, and +MediaType options. + +

Printing On Both Sides of the Paper

+ +

The -o sides=two-sided-short-edge and -o +sides=two-sided-long-edge options will enable duplexing on the +printer, if the printer supports it. The -o +sides=two-sided-short-edge option is suitable for landscape +pages, while the -o sides=two-sided-long-edge option is +suitable for portrait pages: + +

    +lp -o sides=two-sided-short-edge filename ENTER
    +lp -o sides=two-sided-long-edge filename ENTER
    +lpr -o sides=two-sided-long-edge filename ENTER
    +
+ +

The default is to print single-sided: + +

    +lp -o sides=one-sided filename ENTER
    +lpr -o sides=one-sided filename ENTER
    +
+ +

Banner Options

+ +

The following options apply when printing all types of files. + +

Selecting the Banner Page(s)

+ +

The -o jobsheets=start,end option sets the banner page(s) to +use for a job: + +

    +lp -o job-sheets=none filename ENTER
    +lp -o job-sheets=standard filename ENTER
    +lpr -o job-sheets=classified,classified filename ENTER
    +
+ +

If only one banner file is specified, it will be printed before the +files in the job. If a second banner file is specified, it is printed after +the files in the job. + +

The available banner pages depend on the local system configuration; CUPS +includes the following banner files: + +

    + +
  • none - Do not produce a banner page. + +
  • classified - A banner page with a "classified" + label at the top and bottom. + +
  • confidential - A banner page with a + "confidential" label at the top and bottom. + +
  • secret - A banner page with a "secret" label + at the top and bottom. + +
  • standard - A banner page with no label at the + top and bottom. + +
  • topsecret - A banner page with a "top secret" + label at the top and bottom. + +
  • unclassified - A banner page with an + "unclassified" label at the top and bottom. + +
+ +

Document Options

+ +

The following options apply when printing all types of files. + +

Selecting a Range of Pages

+ +

The -o page-ranges=pages option selects a range of +pages for printing: + +

    +lp -o page-ranges=1 filename ENTER
    +lp -o page-ranges=1-4 filename ENTER
    +lp -o page-ranges=1-4,7,9-12 filename ENTER
    +lpr -o page-ranges=1-4,7,9-12 filename ENTER
    +
+ +

As shown above, the pages value can be a single page, a +range of pages, or a collection of page numbers and ranges separated by +commas. The pages will always be printed in ascending order, regardless +of the order of the pages in the page-ranges option. + +

The default is to print all pages. + +

Selecting Even or Odd Pages

+ +

Use the -o page-set=set option to select the even or odd pages: + +

    +lp -o page-set=odd filename ENTER
    +lp -o page-set=even filename ENTER
    +lpr -o page-set=even filename ENTER
    +
+ +

The default is to print all pages. + +

N-Up Printing

+ +

The -o number-up=value option selects N-Up printing. +N-Up printing places multiple document pages on a single printed page. +CUPS supports 1-Up, 2-Up, and 4-Up formats: + +

    +lp -o number-up=1 filename ENTER
    +lp -o number-up=2 filename ENTER
    +lp -o number-up=4 filename ENTER
    +lpr -o number-up=4 filename ENTER
    +
+ +

The default format is 1-Up. + +

Setting the Brightness

+ +

You can control the overall brightness of the printed output using the +-o brightness=percent option: + +

    +lp -o brightness=120 filename ENTER
    +lpr -o brightness=120 filename ENTER
    +
+ +

Values greater than 100 will lighten the print, while values less than +100 will darken it. + +

Setting the Gamma Correction

+ +

You can control the overall gamma correction of the printed output +using the -o gamma=value option: + +

    +lp -o gamma=1700 filename ENTER
    +lpr -o gamma=1700 filename ENTER
    +
+ +

Values greater than 1000 will lighten the print, while values less +than 1000 will darken it. The default gamma is 1000. + +

Text Options

+ +

The following options apply when printing text files. + +

Setting the Number of Characters Per Inch

+ +

The -o cpi=value option sets the number of characters per inch: + +

    +lp -o cpi=10 filename ENTER
    +lp -o cpi=12 filename ENTER
    +lpr -o cpi=17 filename ENTER
    +
+ +

The default characters per inch is 10. + +

Setting the Number of Lines Per Inch

+ +

The -o lpi=value option sets the number of lines per inch: + +

    +lp -o lpi=6 filename ENTER
    +lpr -o lpi=8 filename ENTER
    +
+ +

The default lines per inch is 6. + +

Setting the Number of Columns

+ +

The -o columns=value option sets the number of text columns: + +

    +lp -o columns=2 filename ENTER
    +lpr -o columns=3 filename ENTER
    +
+ +

The default number of columns is 1. + +

Setting the Page Margins

+ +

Normally the page margins are set to the hard limits of the printer. +Use the -o page-left=value, -o +page-right=value, -o page-top=value, and -o +page-bottom=value options to adjust the page margins: + +

    +lp -o page-left=value filename ENTER
    +lp -o page-right=value filename ENTER
    +lp -o page-top=value filename ENTER
    +lp -o page-bottom=value filename ENTER
    +lpr -o page-bottom=value filename ENTER
    +
+ +

The value argument is the margin in points; each point is 1/72 inch +or 0.35mm. + +

Pretty Printing

+ +

The -o prettyprint option puts a header at the top of each page with the +page number, job title (usually the filename), and the date. Also, C and C++ +keywords are highlighted, and comment lines are italicized: + +

    +lp -o prettyprint filename ENTER
    +lpr -o prettyprint filename ENTER
    +
+ +

Image Options

+ +

The following options apply when printing image files. + +

Positioning the Image

+ +

The -o position=name option specifies the position of the +image on the page: + +

    + +
  • center - Center the image on the page (default) + +
  • top - Print the image centered at the top of the page + +
  • left - Print the image centered on the left of page + +
  • right - Print the image centered on the right of the page + +
  • top-left - Print the image at the top left corner of + the page + +
  • top-right - Print the image at the top right corner of + the page + +
  • bottom - Print the image centered at the bottom of + the page + +
  • bottom-left - Print the image at the bottom left + corner of the page + +
  • bottom-right - Print the image at the bottom right + corner of the page + +
+ +

Scaling the Image

+ +

The -o scaling=percent and -o ppi=value +options change the size of a printed image: + +

    +lp -o scaling=percent filename ENTER
    +lp -o ppi=value filename ENTER
    +lpr -o ppi=value filename ENTER
    +
+ +

The percent value is a number from 1 to 800 +specifying the size in relation to the page (not the image.) A +scaling of 100 percent will fill the page as completely as the image +aspect ratio allows. A scaling of 200 percent will print on up to 4 +pages. + +

The ppi value is a number from 1 to 1200 specifying the +resolution of the image in pixels per inch. An image that is 3000x2400 +pixels will print 10x8 inches at 300 pixels per inch, for example. If +the specified resolution makes the image larger than the page, multiple +pages will be printed to satisfy the request. + +

Adjusting the Hue (Tint) of an Image

+ +

The -o hue=value option will adjust the hue of the +printed image, much like the tint control on your television: + +

    +lp -o hue=value filename ENTER
    +lpr -o hue=value filename ENTER
    +
+ + +

The value argument is a number from -360 to 360 and represents the +color hue rotation. The following table summarizes the change you'll see with +different colors: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Originalhue=-45hue=45
RedPurpleYellow-orange
GreenYellow-greenBlue-green
YellowOrangeGreen-yellow
BlueSky-bluePurple
MagentaIndigoCrimson
CyanBlue-greenLight-navy-blue
+ +

The default hue adjustment is 0. + +

Adjusting the Saturation (Color) of an Image

+ +

The -o saturation=percent option adjusts the saturation +of the colors in an image, much like the color knob on your television: + +

    +lp -o saturation=percent filename ENTER
    +lpr -o saturation=percent filename ENTER
    +
+ +

The percent argument specifies the color saturation +from 0 to 200. A color saturation of 0 produces a black-and-white +print, while a value of 200 will make the colors extremely intense. + +

The default saturation is 100. + + +

HP-GL/2 Options

+ +

The following options apply to HP-GL/2 files. + +

Printing in Black

+ +

The -o blackplot option specifies that all pens should +plot in black: + +

    +lp -o blackplot filename ENTER
    +lpr -o blackplot filename ENTER
    +
+ +

The default is to use the colors defined in the plot file or the +standard pen colors defined in the HP-GL/2 reference manual from +Hewlett Packard. + +

Fitting the Plot on the Page

+ +

The -o fitplot option specifies that the plot should be +scaled to fit on the page: + +

    +lp -o fitplot filename ENTER
    +lpr -o fitplot filename ENTER
    +
+ +

The default is to use the absolute distances specified in the plot +file. + +

+ + + +
+ NOTE: + +

This feature depends upon an accurate plot size (PS) + command in the HP-GL/2 file. If no plot size is given in the file + than the HP-GL/2 filter assumes the plot is ANSI E size. +

+ +

Setting the Default Pen Width

+ +

The -o penwidth=value option specifies the default pen +width for HP-GL/2 files: + +

    +lp -o penwidth=value filename ENTER
    +lpr -o penwidth=value filename ENTER
    +
+ +

The pen width value specifies the pen width in micrometers. +The default value of 1000 produces lines that are 1 millimeter in width. +Specifying a pen width of 0 produces lines that are exactly 1 pixel wide. + +

+ + + +
+ NOTE: + +

This option is ignored when the pen widths are set in the + plot file. +

+ +

Raw or Unfiltered Output

+ +

The -o raw option allows you to send files directly to +a printer without filtering. This is sometimes required when printing +from applications that provide their own "printer drivers" for your +printer: + +

    +lp -o raw filename ENTER
    +lpr -o raw filename ENTER
    +
+ +

The -l option can also be used with the +lpr command to send files directly to a printer: + +

    +lpr -l filename ENTER
    +
+ + +

4 - Saving Printer Options and Defaults

+ +

This chapter describes how to save printer options for your printer and +set your own default printer. + +

Printer Options

+ +

Each printer supports a large number of options, which you learned about +in Chapter 3, "Standard Printer Options". +Rather than specifying these options each time you print a file, CUPS allows +you to save them as "default" options for the printer. + +

The lpoptions(1) command saves the options for your printers. +Like the lp and lpr commands, it accepts printer +options using the -o argument: + +

    +lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER
    +lpoptions -o media=Legal -o scaling=100 ENTER
    +
+ +

Once saved, any lp or lpr command will +use them when you print. + +

Setting Options for a Specific Printer

+ +

The previous example shows how to set the options for the default +printer. The -p printer option specifies the options are +for another printer: + +

    +lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER
    +lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER
    +
+ +

Viewing the Current Defaults

+ +

The lpoptions command can also be used to show the current +options by not specifying any new options on the command-line: + +

    +lpoptions ENTER
    +media=A4 sides=two-sided-long-edge
    +lpoptions -p deskjet ENTER
    +media=Legal scaling=100
    +
+ +

Setting the Default Printer

+ +

The administrator normally will set a system-wide default printer +that is normally used as the default printer by everyone. Use the +-d printer option to set your own default printer: + +

    +lpoptions -d deskjet ENTER
    +
+ +

The printer can be local (deskjet) or remote +(deskjet@server). + +

Printer Instances

+ +

Besides setting options for each print queue, CUPS supports +printer instances which allow you to define several different +sets of options for each printer. You specify a printer instance using +the slash (/) character: + +

    +lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER
    +lpoptions -p laserjet/legal -o media=Legal ENTER
    +
+ +

The lp and lpr commands also understand +this notation: + +

    +lp -d laserjet/duplex filename ENTER
    +lpr -P laserjet/legal filename ENTER
    +
+ +

Removing Instances

+ +

Use the -x printer/instance option to remove a printer +instance that you no longer need: + +

    +lpoptions -x laserjet ENTER
    +lpoptions -x laserjet/duplex ENTER
    +lpoptions -x laserjet/legal ENTER
    +
+ +

The -x option only removes the default options for that +printer and instance; the original print queue will remain until deleted +with the lpadmin(8) command by the administrator. + + +

A - Software License +Agreement

+ + + + + diff --git a/doc/svd.html b/doc/svd.html new file mode 100644 index 0000000000..edeacc4cd0 --- /dev/null +++ b/doc/svd.html @@ -0,0 +1,297 @@ + + + + CUPS Software Version Description + + + + + + + +

+

CUPS Software Version Description


+CUPS-SVD-1.1
+Easy Software Products
+Copyright 1997-2001, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Additions + +4 Changes + +A Glossary + +
+

1 Scope

+

1.1 Identification

+ This software version description document provides release +information for the Common UNIX Printing System ("CUPS") Version 1.1. +

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating +systems. It has been developed by Easy +Software Products to promote a standard printing solution for all +UNIX vendors and users. CUPS provides the System V and Berkeley +command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based printing +options to support real-world printing under UNIX.

+

CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters.

+

1.3 Document Overview

+

This software version description document is organized into the +following sections:

+ +

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-IPP-1.1: CUPS Implementation of IPP
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1.x: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+ +

3 Additions

+

CUPS 1.1 includes many new features from the 1.0.x releases.

+

3.1 Filters

+

3.1.1 imagetoraster, imagetops +

+

The image file filters have been upgraded to support conversion of +Microsoft Bitmap ("BMP") and Alias PIX files.

+

3.1.2 pdftops

+

A new pdftops filter has been developed that is based on the +excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is +faster, smaller, and considerably more reliable than the +Ghostscript-based filter in CUPS 1.0.

+

3.1.3 pstoraster

+

The pstoraster filter has been integrated with GNU +GhostScript 5.50. The new RIP supports most Level 3 PostScript language +features.

+

3.1.4 rastertoepson

+

The new rastertoepson filter supports EPSON printers +using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin, +24-pin, Stylus Color, and Stylus Photo printers.

+

3.2 User-Defined Printers and Options

+

The new lpoptions command allows users to configure +default document options and create additional "instances" of existing +printers, each with unique options.

+

The lp, lpr, and lpstat + commands have been upgraded to use this option and printer instance +information automatically.

+

3.3 Daemons

+

CUPS 1.1 includes two new daemons that provide enhanced network +printing support.

+

3.3.1 cups-lpd

+

The cups-lpd daemon provides support for clients using +the Line Printer Daemon protocol.

+

3.3.2 cups-polld

+

The cups-polld daemon provides remote polling services +for the scheduler.

+

3.4 Commands

+

CUPS 1.1 includes several new printing commands.

+

3.4.1 lpoptions

+

The lpoptions command provides user-defined printers +and options.

+

3.4.2 lpmove

+

The lpmove command moves a print job to a new +destination.

+

3.4.3 lpinfo

+

The lpinfo command lists the available PPD files or +devices.

+

3.5 IPP Implementation

+

CUPS 1.1 adds support for the set-job-attributes + extension operation as well as two new CUPS-specific extension +operations to determine which devices and printer drivers are available +on the system.

+

Further information on the CUPS implementation of IPP can be found +in CUPS-IPP-1.1.

+

4 Changes

+

CUPS 1.1 includes many changes from the 1.0.x releases.

+

4.1 Directory Structure

+

The directory structure in CUPS 1.1 has been modified to conform to +the Filesystem Hierarchy Standard, 2.0. The following table describes +the new file locations. +

+ + + + + + + + + + + + + + + + +
Table 1: Directory structure +changes from CUPS 1.0.x to 1.1.x.
DescriptionCUPS 1.0.xCUPS 1.1.x
Backends/var/cups/backend/usr/lib/cups/backend
CGI programs/var/cups/cgi-bin +/usr/lib/cups/cgi-bin
Configuration files/var/cups/conf/etc/cups
Documentation/usr/share/cups/doc +/usr/share/doc/cups
Filter programs/var/cups/filter +/usr/lib/cups/filter
Interface scripts/var/cups/interfaces +/etc/cups/interfaces
Locale data/usr/lib/locale/usr/share/locale
Log files/var/cups/logs/var/log/cups
PPD files/var/cups/ppd/etc/cups/ppd
Request files/var/cups/requests/var/spool/cups
+
+

+

4.2 IPP Implementation

+

CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol.

+

The new scheduler supports the create-job and +send-document operations. In addition, the job-sheets +, job-sheets-default, and job-sheets-supported + attributes are now supported for banner pages.

+

The CUPS-get-printers and CUPS-get-classes + operations have been upgraded to support limited filtering based upon +the printer-type, printer-location, +printer-info, and printer-make-and-model + attributes.

+

The CUPS-add-printer operation now supports the +ppd-name attribute to specify a locally-available PPD file +rather than sending the PPD file from the client with the request.

+

Further information on the CUPS implementation of IPP can be found +in CUPS-IPP-1.1.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/svd.pdf b/doc/svd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..05918d142a635eca69e96fa89da53dba113acc8e GIT binary patch literal 37808 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