From ef416fc25c4af449e930416117bedb12fc9924ba Mon Sep 17 00:00:00 2001
From: jlovell
Date: Fri, 13 Jan 2006 01:51:53 +0000
Subject: [PATCH] Load cups into easysw/current.
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@2 a1ca3aef-8c08-0410-bb20-df032aa958be
---
CGI.txt | 81 +
CHANGES-1.0.txt | 217 +
CHANGES-1.1.txt | 3462 +++
CHANGES.txt | 286 +
CREDITS.txt | 33 +
ENCRYPTION.txt | 142 +
INSTALL.txt | 190 +
LICENSE.html | 1068 +
LICENSE.txt | 964 +
Makedefs.in | 193 +
Makefile | 171 +
README.txt | 290 +
backend/Dependencies | 25 +
backend/Makefile | 178 +
backend/betest.c | 87 +
backend/easysw-firewire-design.txt | 71 +
backend/easysw-firewire-linux.txt | 35 +
backend/ieee1284.c | 373 +
backend/ieee1394-linux.c | 877 +
backend/ieee1394.c | 263 +
backend/ieee1394.h | 103 +
backend/ipp.c | 1468 +
backend/lpd.c | 1149 +
backend/parallel.c | 731 +
backend/scsi-irix.c | 231 +
backend/scsi-linux.c | 249 +
backend/scsi.c | 223 +
backend/serial.c | 1114 +
backend/socket.c | 418 +
backend/test1284.c | 95 +
backend/usb-darwin.c | 1899 ++
backend/usb-unix.c | 620 +
backend/usb.c | 273 +
berkeley/Dependencies | 14 +
berkeley/Makefile | 112 +
berkeley/lpc.c | 524 +
berkeley/lpq.c | 640 +
berkeley/lpr.c | 495 +
berkeley/lprm.c | 284 +
cgi-bin/Dependencies | 50 +
cgi-bin/Makefile | 151 +
cgi-bin/admin.c | 3572 +++
cgi-bin/cgi-private.h | 44 +
cgi-bin/cgi.h | 106 +
cgi-bin/classes.c | 396 +
cgi-bin/help-index.c | 1103 +
cgi-bin/help-index.h | 73 +
cgi-bin/help.c | 362 +
cgi-bin/html.c | 186 +
cgi-bin/ipp-var.c | 896 +
cgi-bin/jobs.c | 238 +
cgi-bin/multipart.dat | Bin 0 -> 50411 bytes
cgi-bin/printers.c | 434 +
cgi-bin/search.c | 368 +
cgi-bin/template.c | 573 +
cgi-bin/testcgi.c | 84 +
cgi-bin/testhi.c | 116 +
cgi-bin/testhi.html | 29 +
cgi-bin/var.c | 1024 +
conf/Makefile | 80 +
conf/classes.conf | 89 +
conf/client.conf | 67 +
conf/cupsd.conf.in | 76 +
conf/mime.convs | 119 +
conf/mime.types | 169 +
conf/pam.darwin | 7 +
conf/pam.irix | 3 +
conf/pam.std.in | 2 +
conf/printcap | 2 +
conf/printers.conf | 96 +
config-scripts/cups-common.m4 | 197 +
config-scripts/cups-compiler.m4 | 200 +
config-scripts/cups-directories.m4 | 279 +
config-scripts/cups-image.m4 | 98 +
config-scripts/cups-largefile.m4 | 61 +
config-scripts/cups-libtool.m4 | 49 +
config-scripts/cups-manpages.m4 | 101 +
config-scripts/cups-network.m4 | 89 +
config-scripts/cups-opsys.m4 | 99 +
config-scripts/cups-pam.m4 | 98 +
config-scripts/cups-scripting.m4 | 91 +
config-scripts/cups-sharedlibs.m4 | 156 +
config-scripts/cups-slp.m4 | 48 +
config-scripts/cups-ssl.m4 | 109 +
config-scripts/cups-threads.m4 | 51 +
config.h.in | 343 +
configure.in | 57 +
cups-config.in | 134 +
cups.osx | 39 +
cups.plist | 7 +
cups.sh.in | 211 +
cups.strings | 9 +
cups/Dependencies | 66 +
cups/Makefile | 342 +
cups/api-array.shtml | 54 +
cups/api-cups.shtml | 48 +
cups/api-filedir.shtml | 66 +
cups/api-filter.shtml | 49 +
cups/api-httpipp.shtml | 48 +
cups/api-ppd.shtml | 48 +
cups/array.c | 828 +
cups/array.h | 83 +
cups/attr.c | 184 +
cups/auth.c | 249 +
cups/backchannel.c | 201 +
cups/backend.h | 50 +
cups/cups.h | 237 +
cups/debug.h | 59 +
cups/dest.c | 865 +
cups/dir.c | 437 +
cups/dir.h | 77 +
cups/emit.c | 816 +
cups/encode.c | 471 +
cups/extended.c | 307 +
cups/file.c | 1680 ++
cups/file.h | 105 +
cups/getputfile.c | 435 +
cups/globals.c | 202 +
cups/globals.h | 156 +
cups/http-addr.c | 545 +
cups/http-addrlist.c | 588 +
cups/http-private.h | 126 +
cups/http-support.c | 1195 +
cups/http.c | 2436 ++
cups/http.h | 473 +
cups/i18n.h | 90 +
cups/ipp-support.c | 332 +
cups/ipp.c | 2763 ++
cups/ipp.h | 477 +
cups/langprintf.c | 140 +
cups/language.c | 1240 +
cups/language.h | 122 +
cups/libcups_s.exp | 21 +
cups/mark.c | 443 +
cups/md5-apple.h | 39 +
cups/md5.c | 344 +
cups/md5.h | 74 +
cups/md5passwd.c | 151 +
cups/normalize.c | 2177 ++
cups/normalize.h | 334 +
cups/options.c | 573 +
cups/page.c | 191 +
cups/ppd.c | 3070 ++
cups/ppd.h | 421 +
cups/sample.ppd | 299 +
cups/snprintf.c | 367 +
cups/string.c | 226 +
cups/string.h | 130 +
cups/tempfile.c | 240 +
cups/testarray.c | 513 +
cups/testfile.c | 400 +
cups/testhttp.c | 514 +
cups/testi18n.c | 791 +
cups/testipp.c | 649 +
cups/testlang.c | 89 +
cups/transcode.c | 1668 ++
cups/transcode.h | 159 +
cups/usersys.c | 463 +
cups/utf8demo.txt | 213 +
cups/util.c | 1892 ++
data/HPGLprolog | 37 +
data/Makefile | 160 +
data/classified | 277 +
data/confidential | 277 +
data/cups.irix | 3 +
data/cups.pam | 2 +
data/cups.suse | 2 +
data/euc-cn.txt | 7536 +++++
data/euc-jp.txt | 15184 ++++++++++
data/euc-kr.txt | 8371 ++++++
data/euc-tw.txt | 17840 ++++++++++++
data/i18n_sdd.txt | 2337 ++
data/iso-8859-1 | 251 +
data/iso-8859-1.txt | 303 +
data/iso-8859-10 | 251 +
data/iso-8859-10.txt | 303 +
data/iso-8859-11.txt | 249 +
data/iso-8859-13 | 251 +
data/iso-8859-13.txt | 299 +
data/iso-8859-14 | 251 +
data/iso-8859-14.txt | 301 +
data/iso-8859-15 | 251 +
data/iso-8859-15.txt | 303 +
data/iso-8859-16.txt | 299 +
data/iso-8859-2 | 253 +
data/iso-8859-2.txt | 303 +
data/iso-8859-3 | 244 +
data/iso-8859-3.txt | 296 +
data/iso-8859-4 | 251 +
data/iso-8859-4.txt | 303 +
data/iso-8859-5 | 251 +
data/iso-8859-5.txt | 303 +
data/iso-8859-6 | 206 +
data/iso-8859-6.txt | 260 +
data/iso-8859-7 | 246 +
data/iso-8859-7.txt | 302 +
data/iso-8859-8 | 214 +
data/iso-8859-8.txt | 270 +
data/iso-8859-9 | 251 +
data/iso-8859-9.txt | 307 +
data/koi8-r | 261 +
data/koi8-r.txt | 257 +
data/koi8-u | 259 +
data/koi8-u.txt | 257 +
data/psglyphs | 1051 +
data/secret | 277 +
data/standard | 261 +
data/testprint.ps | 636 +
data/topsecret | 277 +
data/unclassified | 277 +
data/uni-comb.txt | 299 +
data/uni-fold.txt | 713 +
data/uni-full.txt | 788 +
data/uni-line.txt | 1126 +
data/uni-nfc.txt | 989 +
data/uni-nfd.txt | 1312 +
data/uni-nfkd.txt | 3486 +++
data/uni-prop.txt | 10620 +++++++
data/unibreak.txt | 1354 +
data/utf-8 | 39 +
data/windows-1250 | 254 +
data/windows-1250.txt | 274 +
data/windows-1251 | 258 +
data/windows-1251.txt | 274 +
data/windows-1252 | 254 +
data/windows-1252.txt | 274 +
data/windows-1253 | 243 +
data/windows-1253.txt | 274 +
data/windows-1254 | 252 +
data/windows-1254.txt | 274 +
data/windows-1255 | 236 +
data/windows-1255.txt | 274 +
data/windows-1256 | 259 +
data/windows-1256.txt | 274 +
data/windows-1257 | 247 +
data/windows-1257.txt | 274 +
data/windows-1258 | 250 +
data/windows-1258.txt | 274 +
data/windows-1361.txt | 17396 +++++++++++
data/windows-874 | 228 +
data/windows-874.txt | 274 +
data/windows-932.txt | 9403 ++++++
data/windows-936.txt | 24071 ++++++++++++++++
data/windows-949.txt | 17367 +++++++++++
data/windows-950.txt | 19841 +++++++++++++
doc/Makefile | 167 +
doc/cmp.html | 755 +
doc/cmp.pdf | Bin 0 -> 300850 bytes
doc/cmp.shtml | 737 +
doc/cups.css | 207 +
doc/cupsdoc.css | 9 +
doc/favicon.ico | Bin 0 -> 3638 bytes
doc/figures.sc | Bin 0 -> 75144 bytes
doc/glossary.shtml | 73 +
doc/help/access_log-reference.html | 137 +
doc/help/api-array.html | 399 +
doc/help/api-cups.html | 1464 +
doc/help/api-filedir.html | 661 +
doc/help/api-filter.html | 136 +
doc/help/api-httpipp.html | 3795 +++
doc/help/api-ppd.html | 1250 +
doc/help/classes-conf-reference.html | 540 +
doc/help/client-conf-reference.html | 62 +
doc/help/cupsd-conf-reference.html | 2034 ++
doc/help/error_log-reference.html | 52 +
doc/help/network.html | 431 +
doc/help/overview.html | 504 +
doc/help/page_log-reference.html | 53 +
doc/help/printers-conf-reference.html | 581 +
doc/help/spec-ppd.html | 472 +
doc/help/standard.html.in | 128 +
doc/help/subscriptions-conf-reference.html | 81 +
doc/help/whatsnew.html | 188 +
doc/idd.html | 1083 +
doc/idd.pdf | Bin 0 -> 395751 bytes
doc/idd.shtml | 1445 +
doc/images/accept-jobs.gif | Bin 0 -> 527 bytes
doc/images/add-class.gif | Bin 0 -> 484 bytes
doc/images/add-printer.gif | Bin 0 -> 487 bytes
doc/images/add-this-printer.gif | Bin 0 -> 577 bytes
doc/images/bottom-left.gif | Bin 0 -> 122 bytes
doc/images/bottom-right.gif | Bin 0 -> 123 bytes
doc/images/cancel-all-jobs.gif | Bin 0 -> 568 bytes
doc/images/cancel-job.gif | Bin 0 -> 474 bytes
doc/images/cancel.gif | Bin 0 -> 383 bytes
doc/images/change-settings.gif | Bin 0 -> 615 bytes
doc/images/classes.gif | Bin 0 -> 591 bytes
doc/images/continue.gif | Bin 0 -> 423 bytes
doc/images/cups-black-button-2.2.scm | 80 +
doc/images/cups-block-diagram.gif | Bin 0 -> 11637 bytes
doc/images/cups-green-button-2.2.scm | 80 +
doc/images/cups-large.gif | Bin 0 -> 7457 bytes
doc/images/cups-medium.gif | Bin 0 -> 3163 bytes
doc/images/cups-red-button-2.2.scm | 80 +
doc/images/cups-small.gif | Bin 0 -> 1266 bytes
doc/images/cups-standard-button-2.2.scm | 80 +
doc/images/delete-class.gif | Bin 0 -> 520 bytes
doc/images/delete-printer.gif | Bin 0 -> 508 bytes
doc/images/draft.gif | Bin 0 -> 926 bytes
doc/images/edit-configuration-file.gif | Bin 0 -> 699 bytes
doc/images/esp-logo.gif | Bin 0 -> 2529 bytes
doc/images/happy.gif | Bin 0 -> 3522 bytes
doc/images/help.gif | Bin 0 -> 327 bytes
doc/images/hold-job.gif | Bin 0 -> 436 bytes
doc/images/logo.gif | Bin 0 -> 1958 bytes
doc/images/manage-classes.gif | Bin 0 -> 619 bytes
doc/images/manage-jobs.gif | Bin 0 -> 556 bytes
doc/images/manage-printers.gif | Bin 0 -> 610 bytes
doc/images/manage-server.gif | Bin 0 -> 599 bytes
doc/images/modify-class.gif | Bin 0 -> 559 bytes
doc/images/modify-printer.gif | Bin 0 -> 559 bytes
doc/images/print-test-page.gif | Bin 0 -> 564 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/publish-printer.gif | Bin 0 -> 550 bytes
doc/images/reject-jobs.gif | Bin 0 -> 509 bytes
doc/images/release-job.gif | Bin 0 -> 536 bytes
doc/images/restart-job.gif | Bin 0 -> 493 bytes
doc/images/save-changes.gif | Bin 0 -> 580 bytes
doc/images/search.gif | Bin 0 -> 410 bytes
doc/images/set-allowed-users.gif | Bin 0 -> 673 bytes
doc/images/set-as-default.gif | Bin 0 -> 585 bytes
doc/images/set-printer-options.gif | Bin 0 -> 649 bytes
doc/images/show-active.gif | Bin 0 -> 662 bytes
doc/images/show-all.gif | Bin 0 -> 570 bytes
doc/images/show-ascending.gif | Bin 0 -> 638 bytes
doc/images/show-completed.gif | Bin 0 -> 764 bytes
doc/images/show-descending.gif | Bin 0 -> 659 bytes
doc/images/show-next.gif | Bin 0 -> 514 bytes
doc/images/show-previous.gif | Bin 0 -> 582 bytes
doc/images/start-class.gif | Bin 0 -> 498 bytes
doc/images/start-printer.gif | Bin 0 -> 500 bytes
doc/images/stop-class.gif | Bin 0 -> 500 bytes
doc/images/stop-printer.gif | Bin 0 -> 501 bytes
doc/images/tab-left.gif | Bin 0 -> 46 bytes
doc/images/tab-right.gif | Bin 0 -> 47 bytes
doc/images/top-left.gif | Bin 0 -> 473 bytes
doc/images/top-middle.gif | Bin 0 -> 1144 bytes
doc/images/top-right.gif | Bin 0 -> 121 bytes
doc/images/unpublish-printer.gif | Bin 0 -> 594 bytes
doc/images/use-default-config.gif | Bin 0 -> 864 bytes
doc/images/view-access-log.gif | Bin 0 -> 638 bytes
doc/images/view-error-log.gif | Bin 0 -> 554 bytes
doc/images/view-page-log.gif | Bin 0 -> 590 bytes
doc/index.html.in | 135 +
doc/ipp.html | 1473 +
doc/ipp.pdf | Bin 0 -> 111519 bytes
doc/ipp.shtml | 1994 ++
doc/overview.html | 598 +
doc/overview.pdf | Bin 0 -> 50052 bytes
doc/ppd.shtml | 334 +
doc/printing-overview.shtml | 125 +
doc/references.shtml | 42 +
doc/robots.txt | 31 +
doc/sam.html | 5281 ++++
doc/sam.pdf | Bin 0 -> 273391 bytes
doc/sam.shtml | 5062 ++++
doc/sdd.html | 591 +
doc/sdd.pdf | Bin 0 -> 71633 bytes
doc/sdd.shtml | 564 +
doc/spm.html | 8919 ++++++
doc/spm.pdf | Bin 0 -> 689586 bytes
doc/spm.shtml | 10202 +++++++
doc/sps.html | 297 +
doc/sps.pdf | Bin 0 -> 41182 bytes
doc/sps.shtml | 457 +
doc/ssr.html | 275 +
doc/ssr.pdf | Bin 0 -> 39878 bytes
doc/ssr.shtml | 167 +
doc/stp.html | 262 +
doc/stp.pdf | Bin 0 -> 43329 bytes
doc/stp.shtml | 144 +
doc/sum.html | 1732 ++
doc/sum.pdf | Bin 0 -> 106950 bytes
doc/sum.shtml | 933 +
doc/svd.html | 296 +
doc/svd.pdf | Bin 0 -> 45647 bytes
doc/svd.shtml | 212 +
doc/system-overview.shtml | 19 +
doc/translation.html | 605 +
doc/translation.pdf | Bin 0 -> 50787 bytes
doc/translation.shtml | 734 +
filter/Dependencies | 119 +
filter/Makefile | 285 +
filter/common.c | 471 +
filter/common.h | 92 +
filter/form-main.c | 62 +
filter/form-ps.c | 49 +
filter/form-tree.c | 624 +
filter/form.h | 177 +
filter/gziptoany.c | 131 +
filter/hpgl-attr.c | 454 +
filter/hpgl-char.c | 640 +
filter/hpgl-config.c | 645 +
filter/hpgl-input.c | 258 +
filter/hpgl-main.c | 274 +
filter/hpgl-polygon.c | 394 +
filter/hpgl-prolog.c | 377 +
filter/hpgl-vector.c | 775 +
filter/hpgltops.h | 241 +
filter/image-bmp.c | 546 +
filter/image-colorspace.c | 1565 +
filter/image-gif.c | 697 +
filter/image-jpeg.c | 322 +
filter/image-photocd.c | 327 +
filter/image-pix.c | 244 +
filter/image-png.c | 271 +
filter/image-pnm.c | 312 +
filter/image-private.h | 208 +
filter/image-sgi.c | 293 +
filter/image-sgi.h | 96 +
filter/image-sgilib.c | 859 +
filter/image-sun.c | 406 +
filter/image-tiff.c | 1766 ++
filter/image-zoom.c | 370 +
filter/image.c | 845 +
filter/image.h | 151 +
filter/imagetops.c | 1028 +
filter/imagetoraster.c | 4591 +++
filter/interpret.c | 545 +
filter/pstops.c | 1997 ++
filter/raster.c | 892 +
filter/raster.h | 345 +
filter/rastertoepson.c | 1152 +
filter/rastertohp.c | 888 +
filter/rastertolabel.c | 959 +
filter/testimage.c | 101 +
filter/testraster.c | 210 +
filter/textcommon.c | 1195 +
filter/textcommon.h | 123 +
filter/texttops.c | 1311 +
fonts/Courier | 1494 +
fonts/Courier-Bold | 1652 ++
fonts/Courier-BoldOblique | 1686 ++
fonts/Courier-Oblique | 1448 +
fonts/Makefile | 62 +
fonts/Symbol | 1150 +
install-sh | 251 +
locale/Makefile | 99 +
locale/cups.footer | 5 +
locale/cups.header | 26 +
locale/cups.pot | 2142 ++
locale/cups_fr.po | 2148 ++
locale/locale.txt | 32 +
locale/translate.c | 448 +
man/Makefile | 131 +
man/accept.man | 60 +
man/backend.man | 348 +
man/classes.conf.man | 72 +
man/cups-config.man | 95 +
man/cups-lpd.man | 114 +
man/cups-polld.man | 46 +
man/cupsaddsmb.man | 189 +
man/cupsd.conf.man | 443 +
man/cupsd.man | 61 +
man/cupsenable.man | 67 +
man/cupstestppd.man | 105 +
man/filter.man | 123 +
man/lp.man | 181 +
man/lpadmin.man | 163 +
man/lpc.man | 80 +
man/lpinfo.man | 60 +
man/lpmove.man | 53 +
man/lpoptions.man | 128 +
man/lppasswd.man | 61 +
man/lpq.man | 57 +
man/lpr.man | 107 +
man/lprm.man | 54 +
man/lpstat.man | 140 +
man/mantohtml.c | 642 +
man/mime.convs.man | 54 +
man/mime.types.man | 102 +
man/printers.conf.man | 73 +
notifier/Dependencies | 8 +
notifier/Makefile | 91 +
notifier/mailto.c | 50 +
notifier/testnotify.c | 285 +
packaging/LICENSE.rtf | 462 +
packaging/WELCOME.rtf | 24 +
packaging/cups-desc.plist.in | 15 +
packaging/cups-info.plist.in | 24 +
packaging/cups.list.in | 453 +
packaging/cups.spec.in | 267 +
packaging/installer.tif | Bin 0 -> 6580 bytes
packaging/installer.xcf.gz | Bin 0 -> 7461 bytes
pdftops/Annot.cxx | 317 +
pdftops/Annot.h | 73 +
pdftops/Array.cxx | 73 +
pdftops/Array.h | 58 +
pdftops/BuiltinFont.cxx | 65 +
pdftops/BuiltinFont.h | 57 +
pdftops/BuiltinFontTables.cxx | 4284 +++
pdftops/BuiltinFontTables.h | 23 +
pdftops/CMap.cxx | 408 +
pdftops/CMap.h | 102 +
pdftops/COPYING | 339 +
pdftops/Catalog.cxx | 353 +
pdftops/Catalog.h | 92 +
pdftops/CharCodeToUnicode.cxx | 540 +
pdftops/CharCodeToUnicode.h | 117 +
pdftops/CharTypes.h | 24 +
pdftops/CompactFontTables.h | 464 +
pdftops/Decrypt.cxx | 411 +
pdftops/Decrypt.h | 63 +
pdftops/Dependencies | 149 +
pdftops/Dict.cxx | 95 +
pdftops/Dict.h | 77 +
pdftops/Error.cxx | 38 +
pdftops/Error.h | 23 +
pdftops/ErrorCodes.h | 36 +
pdftops/FoFiBase.cxx | 156 +
pdftops/FoFiBase.h | 57 +
pdftops/FoFiEncodings.cxx | 994 +
pdftops/FoFiEncodings.h | 36 +
pdftops/FoFiTrueType.cxx | 1753 ++
pdftops/FoFiTrueType.h | 140 +
pdftops/FoFiType1.cxx | 207 +
pdftops/FoFiType1.h | 59 +
pdftops/FoFiType1C.cxx | 2481 ++
pdftops/FoFiType1C.h | 232 +
pdftops/FontEncodingTables.cxx | 1824 ++
pdftops/FontEncodingTables.h | 20 +
pdftops/Function.cxx | 1536 +
pdftops/Function.h | 225 +
pdftops/GHash.cxx | 380 +
pdftops/GHash.h | 78 +
pdftops/GList.cxx | 97 +
pdftops/GList.h | 96 +
pdftops/GMutex.h | 49 +
pdftops/GString.cxx | 319 +
pdftops/GString.h | 97 +
pdftops/Gfx.cxx | 3623 +++
pdftops/Gfx.h | 294 +
pdftops/GfxFont.cxx | 1546 +
pdftops/GfxFont.h | 315 +
pdftops/GfxState.cxx | 3946 +++
pdftops/GfxState.h | 1206 +
pdftops/GlobalParams.cxx | 1995 ++
pdftops/GlobalParams.h | 336 +
pdftops/JArithmeticDecoder.cxx | 322 +
pdftops/JArithmeticDecoder.h | 109 +
pdftops/JBIG2Stream.cxx | 3386 +++
pdftops/JBIG2Stream.h | 143 +
pdftops/JPXStream.cxx | 2953 ++
pdftops/JPXStream.h | 349 +
pdftops/Lexer.cxx | 485 +
pdftops/Lexer.h | 80 +
pdftops/Link.cxx | 907 +
pdftops/Link.h | 409 +
pdftops/Makefile | 158 +
pdftops/NameToCharCode.cxx | 116 +
pdftops/NameToCharCode.h | 42 +
pdftops/NameToUnicodeTable.h | 1097 +
pdftops/Object.cxx | 231 +
pdftops/Object.h | 303 +
pdftops/Outline.cxx | 151 +
pdftops/Outline.h | 76 +
pdftops/OutputDev.cxx | 129 +
pdftops/OutputDev.h | 205 +
pdftops/PDFDoc.cxx | 431 +
pdftops/PDFDoc.h | 182 +
pdftops/PDFDocEncoding.cxx | 44 +
pdftops/PDFDocEncoding.h | 16 +
pdftops/PSOutputDev.cxx | 4976 ++++
pdftops/PSOutputDev.h | 354 +
pdftops/PSTokenizer.cxx | 135 +
pdftops/PSTokenizer.h | 41 +
pdftops/Page.cxx | 367 +
pdftops/Page.h | 175 +
pdftops/Parser.cxx | 214 +
pdftops/Parser.h | 56 +
pdftops/README | 446 +
pdftops/SecurityHandler.cxx | 378 +
pdftops/SecurityHandler.h | 155 +
pdftops/Splash.cxx | 3191 ++
pdftops/Splash.h | 204 +
pdftops/SplashBitmap.cxx | 243 +
pdftops/SplashBitmap.h | 55 +
pdftops/SplashClip.cxx | 270 +
pdftops/SplashClip.h | 97 +
pdftops/SplashErrorCodes.h | 32 +
pdftops/SplashFTFont.cxx | 320 +
pdftops/SplashFTFont.h | 55 +
pdftops/SplashFTFontEngine.cxx | 144 +
pdftops/SplashFTFontEngine.h | 61 +
pdftops/SplashFTFontFile.cxx | 111 +
pdftops/SplashFTFontFile.h | 70 +
pdftops/SplashFont.cxx | 172 +
pdftops/SplashFont.h | 97 +
pdftops/SplashFontEngine.cxx | 253 +
pdftops/SplashFontEngine.h | 86 +
pdftops/SplashFontFile.cxx | 55 +
pdftops/SplashFontFile.h | 60 +
pdftops/SplashFontFileID.cxx | 23 +
pdftops/SplashFontFileID.h | 30 +
pdftops/SplashGlyphBitmap.h | 26 +
pdftops/SplashMath.h | 78 +
pdftops/SplashOutputDev.cxx | 2640 ++
pdftops/SplashOutputDev.h | 222 +
pdftops/SplashPath.cxx | 178 +
pdftops/SplashPath.h | 112 +
pdftops/SplashPattern.cxx | 68 +
pdftops/SplashPattern.h | 90 +
pdftops/SplashScreen.cxx | 141 +
pdftops/SplashScreen.h | 50 +
pdftops/SplashState.cxx | 110 +
pdftops/SplashState.h | 91 +
pdftops/SplashT1Font.cxx | 264 +
pdftops/SplashT1Font.h | 53 +
pdftops/SplashT1FontEngine.cxx | 124 +
pdftops/SplashT1FontEngine.h | 53 +
pdftops/SplashT1FontFile.cxx | 96 +
pdftops/SplashT1FontFile.h | 57 +
pdftops/SplashTypes.h | 139 +
pdftops/SplashXPath.cxx | 414 +
pdftops/SplashXPath.h | 92 +
pdftops/SplashXPathScanner.cxx | 277 +
pdftops/SplashXPathScanner.h | 74 +
pdftops/Stream-CCITT.h | 459 +
pdftops/Stream.cxx | 4572 +++
pdftops/Stream.h | 846 +
pdftops/UTF8.h | 56 +
pdftops/UnicodeMap.cxx | 293 +
pdftops/UnicodeMap.h | 123 +
pdftops/UnicodeMapTables.h | 361 +
pdftops/UnicodeTypeTable.cxx | 949 +
pdftops/UnicodeTypeTable.h | 20 +
pdftops/XRef.cxx | 888 +
pdftops/XRef.h | 131 +
pdftops/XpdfPluginAPI.cxx | 262 +
pdftops/XpdfPluginAPI.h | 323 +
pdftops/config.h | 112 +
pdftops/gfile.cxx | 707 +
pdftops/gfile.h | 126 +
pdftops/gmem.c | 229 +
pdftops/gmem.h | 62 +
pdftops/gmempp.cxx | 32 +
pdftops/gtypes.h | 29 +
pdftops/parseargs.c | 190 +
pdftops/parseargs.h | 71 +
pdftops/pdftops.cxx | 345 +
ppd/Makefile | 64 +
ppd/deskjet.ppd | 199 +
ppd/deskjet2.ppd | 218 +
ppd/dymo.ppd | 156 +
ppd/epson24.ppd | 139 +
ppd/epson9.ppd | 137 +
ppd/laserjet.ppd | 201 +
ppd/okidat24.ppd | 129 +
ppd/okidata9.ppd | 127 +
ppd/stcolor.ppd | 133 +
ppd/stcolor2.ppd | 133 +
ppd/stphoto.ppd | 133 +
ppd/stphoto2.ppd | 133 +
ppd/zebra.ppd | 332 +
ppd/zebracpl.ppd | 276 +
ppd/zebraep1.ppd | 179 +
ppd/zebraep2.ppd | 191 +
pstoraster/README.pstoraster | 73 +
pstoraster/cups.mak | 53 +
pstoraster/gdevcups.c | 4464 +++
pstoraster/gs707-lib.patch | 110 +
pstoraster/gs811-lib.patch | 110 +
pstoraster/pstopxl | 67 +
pstoraster/pstopxl.in | 67 +
pstoraster/pstoraster | 52 +
pstoraster/pstoraster.convs | 29 +
pstoraster/pstoraster.in | 62 +
pstoraster/pxlcolor.ppd | 205 +
pstoraster/pxlmono.ppd | 199 +
scheduler/Dependencies | 176 +
scheduler/Makefile | 243 +
scheduler/auth.c | 2116 ++
scheduler/auth.h | 163 +
scheduler/banners.c | 210 +
scheduler/banners.h | 57 +
scheduler/cert.c | 296 +
scheduler/cert.h | 60 +
scheduler/classes.c | 844 +
scheduler/classes.h | 46 +
scheduler/client.c | 3484 +++
scheduler/client.h | 134 +
scheduler/conf.c | 3048 ++
scheduler/conf.h | 211 +
scheduler/cups-deviced.c | 441 +
scheduler/cups-driverd.c | 1080 +
scheduler/cups-lpd.c | 1441 +
scheduler/cups-polld.c | 405 +
scheduler/cups.pam | 2 +
scheduler/cupsd.h | 201 +
scheduler/dirsvc.c | 2635 ++
scheduler/dirsvc.h | 162 +
scheduler/env.c | 224 +
scheduler/filter.c | 326 +
scheduler/ipp.c | 8986 ++++++
scheduler/job.c | 2718 ++
scheduler/job.h | 120 +
scheduler/listen.c | 398 +
scheduler/log.c | 553 +
scheduler/main.c | 1508 +
scheduler/mime.c | 573 +
scheduler/mime.h | 147 +
scheduler/network.c | 576 +
scheduler/network.h | 64 +
scheduler/policy.c | 337 +
scheduler/policy.h | 66 +
scheduler/printers.c | 2874 ++
scheduler/printers.h | 146 +
scheduler/process.c | 224 +
scheduler/quotas.c | 240 +
scheduler/server.c | 206 +
scheduler/statbuf.c | 330 +
scheduler/statbuf.h | 59 +
scheduler/subscriptions.c | 1530 +
scheduler/subscriptions.h | 175 +
scheduler/testdirsvc.c | 275 +
scheduler/testmime.c | 246 +
scheduler/testspeed.c | 305 +
scheduler/type.c | 1165 +
scheduler/util.c | 279 +
scheduler/util.h | 59 +
scripting/java/CUPSPrinter.java | 438 +
.../java/classes/com/easysw/cups/Cups.class | Bin 0 -> 12601 bytes
.../classes/com/easysw/cups/CupsJob.class | Bin 0 -> 2830 bytes
.../classes/com/easysw/cups/CupsPrinter.class | Bin 0 -> 11088 bytes
.../java/classes/com/easysw/cups/IPP.class | Bin 0 -> 2100 bytes
.../com/easysw/cups/IPPAttribute.class | Bin 0 -> 6695 bytes
.../com/easysw/cups/IPPBase64Encoder.class | Bin 0 -> 362 bytes
.../classes/com/easysw/cups/IPPCalendar.class | Bin 0 -> 382 bytes
.../classes/com/easysw/cups/IPPDefs.class | Bin 0 -> 7640 bytes
.../classes/com/easysw/cups/IPPError.class | Bin 0 -> 2663 bytes
.../classes/com/easysw/cups/IPPHttp.class | Bin 0 -> 16865 bytes
.../java/classes/com/easysw/cups/IPPMD5.class | Bin 0 -> 1912 bytes
.../classes/com/easysw/cups/IPPRequest.class | Bin 0 -> 627 bytes
.../classes/com/easysw/cups/IPPStatus.class | Bin 0 -> 2402 bytes
.../com/easysw/cups/IPPURLConnection.class | Bin 0 -> 413 bytes
.../classes/com/easysw/cups/IPPValue.class | Bin 0 -> 1979 bytes
scripting/java/cups.jar | Bin 0 -> 37208 bytes
scripting/java/docs/allclasses-frame.html | 49 +
scripting/java/docs/com/easysw/cups/Cups.html | 600 +
.../java/docs/com/easysw/cups/CupsJob.html | 547 +
.../docs/com/easysw/cups/CupsPrinter.html | 533 +
scripting/java/docs/com/easysw/cups/IPP.html | 417 +
.../docs/com/easysw/cups/IPPAttribute.html | 466 +
.../java/docs/com/easysw/cups/IPPDefs.html | 3330 +++
.../java/docs/com/easysw/cups/IPPError.html | 178 +
.../java/docs/com/easysw/cups/IPPHttp.html | 2596 ++
.../java/docs/com/easysw/cups/IPPRequest.html | 251 +
.../java/docs/com/easysw/cups/IPPStatus.html | 185 +
.../com/easysw/cups/IPPURLConnection.html | 262 +
.../java/docs/com/easysw/cups/IPPValue.html | 376 +
scripting/java/docs/deprecated-list.html | 89 +
scripting/java/docs/help-doc.html | 138 +
scripting/java/docs/index-all.html | 1588 +
scripting/java/docs/index.html | 22 +
scripting/java/docs/overview-tree.html | 101 +
scripting/java/docs/package-list | 1 +
scripting/java/docs/packages.html | 26 +
scripting/java/docs/serialized-form.html | 89 +
scripting/java/docs/stylesheet.css | 29 +
scripting/java/example/GLP.class | Bin 0 -> 1163 bytes
scripting/java/example/GLP.java | 59 +
scripting/java/example/GLPcolors.class | Bin 0 -> 838 bytes
scripting/java/example/GLPcolors.java | 22 +
scripting/java/example/GLPdetail.class | Bin 0 -> 5600 bytes
scripting/java/example/GLPdetail.java | 279 +
scripting/java/example/GLPjobList.class | Bin 0 -> 3587 bytes
scripting/java/example/GLPjobList.java | 150 +
scripting/java/example/GLPjobTableModel.class | Bin 0 -> 1849 bytes
scripting/java/example/GLPjobTableModel.java | 104 +
scripting/java/example/GLPoptions$1.class | Bin 0 -> 1025 bytes
.../example/GLPoptions$MyTextListener.class | Bin 0 -> 1217 bytes
scripting/java/example/GLPoptions.class | Bin 0 -> 11082 bytes
scripting/java/example/GLPoptions.java | 662 +
scripting/java/example/GLPprinterDetail.class | Bin 0 -> 4832 bytes
scripting/java/example/GLPprinterDetail.java | 244 +
scripting/java/example/GLPprinters.class | Bin 0 -> 8749 bytes
scripting/java/example/GLPprinters.java | 509 +
scripting/java/example/GLPsearch.class | Bin 0 -> 2428 bytes
scripting/java/example/GLPsearch.java | 121 +
.../example/GLPsearchProgressPanel$1.class | Bin 0 -> 2470 bytes
.../example/GLPsearchProgressPanel$2.class | Bin 0 -> 1188 bytes
...LPsearchProgressPanel$ButtonListener.class | Bin 0 -> 1686 bytes
.../java/example/GLPsearchProgressPanel.class | Bin 0 -> 2709 bytes
.../java/example/GLPsearchProgressPanel.java | 195 +
scripting/java/example/GLPserver.class | Bin 0 -> 4304 bytes
scripting/java/example/GLPserver.java | 192 +
scripting/java/example/GLPtabs$1.class | Bin 0 -> 1097 bytes
scripting/java/example/GLPtabs.class | Bin 0 -> 2611 bytes
scripting/java/example/GLPtabs.java | 117 +
scripting/java/example/GLPvars.class | Bin 0 -> 1592 bytes
scripting/java/example/GLPvars.java | 93 +
scripting/java/example/buildit | 4 +
scripting/java/example/class.list | 13 +
scripting/java/example/images/left.gif | Bin 0 -> 110 bytes
.../java/example/images/print-test-page.gif | Bin 0 -> 519 bytes
.../java/example/images/printer-idle.gif | Bin 0 -> 706 bytes
.../java/example/images/printer-stopped.gif | Bin 0 -> 794 bytes
scripting/java/example/images/restart-job.gif | Bin 0 -> 440 bytes
scripting/java/example/images/show-active.gif | Bin 0 -> 581 bytes
.../java/example/images/show-completed.gif | Bin 0 -> 657 bytes
scripting/java/example/runit | 2 +
scripting/java/src/com/easysw/cups/Cups.java | 1413 +
.../java/src/com/easysw/cups/CupsJob.java | 216 +
.../java/src/com/easysw/cups/CupsPrinter.java | 837 +
scripting/java/src/com/easysw/cups/IPP.java | 251 +
.../src/com/easysw/cups/IPPAttribute.java | 593 +
.../src/com/easysw/cups/IPPBase64Encoder.java | 46 +
.../java/src/com/easysw/cups/IPPCalendar.java | 62 +
.../java/src/com/easysw/cups/IPPDefs.java | 310 +
.../java/src/com/easysw/cups/IPPError.java | 159 +
.../java/src/com/easysw/cups/IPPHttp.java | 1353 +
.../java/src/com/easysw/cups/IPPMD5.java | 134 +
.../java/src/com/easysw/cups/IPPRequest.java | 97 +
.../java/src/com/easysw/cups/IPPStatus.java | 195 +
.../src/com/easysw/cups/IPPURLConnection.java | 78 +
.../java/src/com/easysw/cups/IPPValue.java | 264 +
scripting/java/src/com/easysw/cups/buildit | 9 +
scripting/java/src/com/easysw/cups/class.list | 14 +
scripting/java/src/com/easysw/cups/cups.nfo | 34 +
scripting/perl/CUPS.pm | 144 +
scripting/perl/CUPS.xs | 270 +
scripting/perl/Makefile.PL | 17 +
scripting/perl/README | 35 +
scripting/perl/test.pl | 17 +
scripting/php/Dependencies | 6 +
scripting/php/Example/phpcups.inc.php4 | 310 +
scripting/php/Makefile | 107 +
scripting/php/README | 21 +
scripting/php/config.m4 | 60 +
scripting/php/php_phpcups.h | 87 +
scripting/php/phpcups.c | 1357 +
scripting/php/phpcups.php | 53 +
standards/pwg5100.1.pdf | Bin 0 -> 37359 bytes
standards/pwg5100.2.pdf | Bin 0 -> 37360 bytes
standards/pwg5100.3.pdf | Bin 0 -> 262279 bytes
standards/pwg5100.4.pdf | Bin 0 -> 150078 bytes
standards/rfc1179.txt | 787 +
standards/rfc1321.txt | 1179 +
standards/rfc2222.txt | 899 +
standards/rfc2246.txt | 4483 +++
standards/rfc2487.txt | 451 +
standards/rfc2554.txt | 619 +
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 ++++++++
standards/rfc2965.txt | 1459 +
standards/rfc3239.txt | 843 +
standards/rfc3380.txt | 3307 +++
standards/rfc3381.txt | 955 +
standards/rfc3382.txt | 2131 ++
standards/rfc3510.txt | 899 +
standards/rfc3986.txt | 3419 +++
standards/rfc3995.txt | 5323 ++++
standards/rfc3996.txt | 1739 ++
standards/rfc3997.txt | 955 +
standards/rfc3998.txt | 2579 ++
standards/wd-ippmailto10-20050519.pdf | Bin 0 -> 75741 bytes
systemv/Dependencies | 35 +
systemv/Makefile | 195 +
systemv/accept.c | 294 +
systemv/cancel.c | 390 +
systemv/cupsaddsmb.c | 1032 +
systemv/cupstestppd.c | 1386 +
systemv/lp.c | 813 +
systemv/lpadmin.c | 2173 ++
systemv/lpinfo.c | 466 +
systemv/lpmove.c | 241 +
systemv/lpoptions.c | 456 +
systemv/lppasswd.c | 517 +
systemv/lpstat.c | 2208 ++
templates/Makefile | 110 +
templates/add-class.tmpl | 33 +
templates/add-printer.tmpl | 28 +
templates/admin-op.tmpl | 1 +
templates/admin.tmpl | 71 +
templates/choose-device.tmpl | 26 +
templates/choose-make.tmpl | 42 +
templates/choose-model.tmpl | 34 +
templates/choose-serial.tmpl | 47 +
templates/choose-uri.tmpl | 40 +
templates/class-added.tmpl | 2 +
templates/class-confirm.tmpl | 7 +
templates/class-deleted.tmpl | 1 +
templates/class-modified.tmpl | 2 +
templates/classes.tmpl | 60 +
templates/edit-config.tmpl.in | 90 +
templates/error.tmpl | 3 +
templates/header.tmpl | 62 +
templates/help-header.tmpl | 28 +
templates/job-cancel.tmpl | 1 +
templates/job-hold.tmpl | 1 +
templates/job-op.tmpl | 1 +
templates/job-release.tmpl | 1 +
templates/job-restart.tmpl | 1 +
templates/jobs-header.tmpl | 17 +
templates/jobs.tmpl | 44 +
templates/modify-class.tmpl | 34 +
templates/modify-printer.tmpl | 29 +
templates/option-boolean.tmpl | 6 +
templates/option-conflict.tmpl | 7 +
templates/option-header.tmpl | 3 +
templates/option-pickmany.tmpl | 6 +
templates/option-pickone.tmpl | 6 +
templates/option-trailer.tmpl | 5 +
templates/page.tmpl | 7 +
templates/printer-accept.tmpl | 1 +
templates/printer-added.tmpl | 2 +
templates/printer-configured.tmpl | 2 +
templates/printer-confirm.tmpl | 7 +
templates/printer-default.tmpl | 4 +
templates/printer-deleted.tmpl | 1 +
templates/printer-modified.tmpl | 2 +
templates/printer-purge.tmpl | 1 +
templates/printer-reject.tmpl | 1 +
templates/printer-start.tmpl | 2 +
templates/printer-stop.tmpl | 2 +
templates/printers.tmpl | 68 +
templates/restart.tmpl | 1 +
templates/search.tmpl | 10 +
templates/set-printer-options-header.tmpl | 3 +
templates/set-printer-options-trailer.tmpl | 1 +
templates/test-page.tmpl | 2 +
templates/trailer.tmpl | 21 +
templates/users.tmpl | 25 +
test/4.1-requests.test | 140 +
test/4.2-cups-printer-ops.test | 241 +
test/4.3-job-ops.test | 301 +
test/4.4-subscription-ops.test | 122 +
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 | 71 +
test/5.6-lpr.sh | 71 +
test/5.7-lprm.sh | 52 +
test/5.8-cancel.sh | 52 +
test/5.9-lpinfo.sh | 52 +
test/Dependencies | 4 +
test/Makefile | 77 +
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 | 786 +
test/print-job-hold.test | 33 +
test/print-job.test | 32 +
test/run-stp-tests.sh | 553 +
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 | 594 +
test/testfile.txt | 60 +
test/testhp.ppd | 195 +
test/testps.ppd | 192 +
tools/makesrcdist | 71 +
tools/testosx | 87 +
tools/testrpm | 28 +
vcnet/config.h | 352 +
vcnet/cups.sln | 21 +
vcnet/libcups2.def | 247 +
vcnet/libcups2.vcproj | 286 +
983 files changed, 606921 insertions(+)
create mode 100644 CGI.txt
create mode 100644 CHANGES-1.0.txt
create mode 100644 CHANGES-1.1.txt
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 LICENSE.txt
create mode 100644 Makedefs.in
create mode 100644 Makefile
create mode 100644 README.txt
create mode 100644 backend/Dependencies
create mode 100644 backend/Makefile
create mode 100644 backend/betest.c
create mode 100644 backend/easysw-firewire-design.txt
create mode 100644 backend/easysw-firewire-linux.txt
create mode 100644 backend/ieee1284.c
create mode 100644 backend/ieee1394-linux.c
create mode 100644 backend/ieee1394.c
create mode 100644 backend/ieee1394.h
create mode 100644 backend/ipp.c
create mode 100644 backend/lpd.c
create mode 100644 backend/parallel.c
create mode 100644 backend/scsi-irix.c
create mode 100644 backend/scsi-linux.c
create mode 100644 backend/scsi.c
create mode 100644 backend/serial.c
create mode 100644 backend/socket.c
create mode 100644 backend/test1284.c
create mode 100644 backend/usb-darwin.c
create mode 100644 backend/usb-unix.c
create mode 100644 backend/usb.c
create mode 100644 berkeley/Dependencies
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/Dependencies
create mode 100644 cgi-bin/Makefile
create mode 100644 cgi-bin/admin.c
create mode 100644 cgi-bin/cgi-private.h
create mode 100644 cgi-bin/cgi.h
create mode 100644 cgi-bin/classes.c
create mode 100644 cgi-bin/help-index.c
create mode 100644 cgi-bin/help-index.h
create mode 100644 cgi-bin/help.c
create mode 100644 cgi-bin/html.c
create mode 100644 cgi-bin/ipp-var.c
create mode 100644 cgi-bin/jobs.c
create mode 100644 cgi-bin/multipart.dat
create mode 100644 cgi-bin/printers.c
create mode 100644 cgi-bin/search.c
create mode 100644 cgi-bin/template.c
create mode 100644 cgi-bin/testcgi.c
create mode 100644 cgi-bin/testhi.c
create mode 100644 cgi-bin/testhi.html
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.in
create mode 100644 conf/mime.convs
create mode 100644 conf/mime.types
create mode 100644 conf/pam.darwin
create mode 100644 conf/pam.irix
create mode 100644 conf/pam.std.in
create mode 100644 conf/printcap
create mode 100644 conf/printers.conf
create mode 100644 config-scripts/cups-common.m4
create mode 100644 config-scripts/cups-compiler.m4
create mode 100644 config-scripts/cups-directories.m4
create mode 100644 config-scripts/cups-image.m4
create mode 100644 config-scripts/cups-largefile.m4
create mode 100644 config-scripts/cups-libtool.m4
create mode 100644 config-scripts/cups-manpages.m4
create mode 100644 config-scripts/cups-network.m4
create mode 100644 config-scripts/cups-opsys.m4
create mode 100644 config-scripts/cups-pam.m4
create mode 100644 config-scripts/cups-scripting.m4
create mode 100644 config-scripts/cups-sharedlibs.m4
create mode 100644 config-scripts/cups-slp.m4
create mode 100644 config-scripts/cups-ssl.m4
create mode 100644 config-scripts/cups-threads.m4
create mode 100644 config.h.in
create mode 100644 configure.in
create mode 100755 cups-config.in
create mode 100644 cups.osx
create mode 100644 cups.plist
create mode 100755 cups.sh.in
create mode 100644 cups.strings
create mode 100644 cups/Dependencies
create mode 100644 cups/Makefile
create mode 100644 cups/api-array.shtml
create mode 100644 cups/api-cups.shtml
create mode 100644 cups/api-filedir.shtml
create mode 100644 cups/api-filter.shtml
create mode 100644 cups/api-httpipp.shtml
create mode 100644 cups/api-ppd.shtml
create mode 100644 cups/array.c
create mode 100644 cups/array.h
create mode 100644 cups/attr.c
create mode 100644 cups/auth.c
create mode 100644 cups/backchannel.c
create mode 100644 cups/backend.h
create mode 100644 cups/cups.h
create mode 100644 cups/debug.h
create mode 100644 cups/dest.c
create mode 100644 cups/dir.c
create mode 100644 cups/dir.h
create mode 100644 cups/emit.c
create mode 100644 cups/encode.c
create mode 100644 cups/extended.c
create mode 100644 cups/file.c
create mode 100644 cups/file.h
create mode 100644 cups/getputfile.c
create mode 100644 cups/globals.c
create mode 100644 cups/globals.h
create mode 100644 cups/http-addr.c
create mode 100644 cups/http-addrlist.c
create mode 100644 cups/http-private.h
create mode 100644 cups/http-support.c
create mode 100644 cups/http.c
create mode 100644 cups/http.h
create mode 100644 cups/i18n.h
create mode 100644 cups/ipp-support.c
create mode 100644 cups/ipp.c
create mode 100644 cups/ipp.h
create mode 100644 cups/langprintf.c
create mode 100644 cups/language.c
create mode 100644 cups/language.h
create mode 100644 cups/libcups_s.exp
create mode 100644 cups/mark.c
create mode 100644 cups/md5-apple.h
create mode 100644 cups/md5.c
create mode 100644 cups/md5.h
create mode 100644 cups/md5passwd.c
create mode 100644 cups/normalize.c
create mode 100644 cups/normalize.h
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/sample.ppd
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/testarray.c
create mode 100644 cups/testfile.c
create mode 100644 cups/testhttp.c
create mode 100644 cups/testi18n.c
create mode 100644 cups/testipp.c
create mode 100644 cups/testlang.c
create mode 100644 cups/transcode.c
create mode 100644 cups/transcode.h
create mode 100644 cups/usersys.c
create mode 100644 cups/utf8demo.txt
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.irix
create mode 100644 data/cups.pam
create mode 100644 data/cups.suse
create mode 100644 data/euc-cn.txt
create mode 100644 data/euc-jp.txt
create mode 100644 data/euc-kr.txt
create mode 100644 data/euc-tw.txt
create mode 100644 data/i18n_sdd.txt
create mode 100644 data/iso-8859-1
create mode 100644 data/iso-8859-1.txt
create mode 100644 data/iso-8859-10
create mode 100644 data/iso-8859-10.txt
create mode 100644 data/iso-8859-11.txt
create mode 100644 data/iso-8859-13
create mode 100644 data/iso-8859-13.txt
create mode 100644 data/iso-8859-14
create mode 100644 data/iso-8859-14.txt
create mode 100644 data/iso-8859-15
create mode 100644 data/iso-8859-15.txt
create mode 100644 data/iso-8859-16.txt
create mode 100644 data/iso-8859-2
create mode 100644 data/iso-8859-2.txt
create mode 100644 data/iso-8859-3
create mode 100644 data/iso-8859-3.txt
create mode 100644 data/iso-8859-4
create mode 100644 data/iso-8859-4.txt
create mode 100644 data/iso-8859-5
create mode 100644 data/iso-8859-5.txt
create mode 100644 data/iso-8859-6
create mode 100644 data/iso-8859-6.txt
create mode 100644 data/iso-8859-7
create mode 100644 data/iso-8859-7.txt
create mode 100644 data/iso-8859-8
create mode 100644 data/iso-8859-8.txt
create mode 100644 data/iso-8859-9
create mode 100644 data/iso-8859-9.txt
create mode 100644 data/koi8-r
create mode 100644 data/koi8-r.txt
create mode 100644 data/koi8-u
create mode 100644 data/koi8-u.txt
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/uni-comb.txt
create mode 100644 data/uni-fold.txt
create mode 100644 data/uni-full.txt
create mode 100644 data/uni-line.txt
create mode 100644 data/uni-nfc.txt
create mode 100644 data/uni-nfd.txt
create mode 100644 data/uni-nfkd.txt
create mode 100644 data/uni-prop.txt
create mode 100644 data/unibreak.txt
create mode 100644 data/utf-8
create mode 100644 data/windows-1250
create mode 100644 data/windows-1250.txt
create mode 100644 data/windows-1251
create mode 100644 data/windows-1251.txt
create mode 100644 data/windows-1252
create mode 100644 data/windows-1252.txt
create mode 100644 data/windows-1253
create mode 100644 data/windows-1253.txt
create mode 100644 data/windows-1254
create mode 100644 data/windows-1254.txt
create mode 100644 data/windows-1255
create mode 100644 data/windows-1255.txt
create mode 100644 data/windows-1256
create mode 100644 data/windows-1256.txt
create mode 100644 data/windows-1257
create mode 100644 data/windows-1257.txt
create mode 100644 data/windows-1258
create mode 100644 data/windows-1258.txt
create mode 100644 data/windows-1361.txt
create mode 100644 data/windows-874
create mode 100644 data/windows-874.txt
create mode 100644 data/windows-932.txt
create mode 100644 data/windows-936.txt
create mode 100644 data/windows-949.txt
create mode 100644 data/windows-950.txt
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/favicon.ico
create mode 100644 doc/figures.sc
create mode 100644 doc/glossary.shtml
create mode 100644 doc/help/access_log-reference.html
create mode 100644 doc/help/api-array.html
create mode 100644 doc/help/api-cups.html
create mode 100644 doc/help/api-filedir.html
create mode 100644 doc/help/api-filter.html
create mode 100644 doc/help/api-httpipp.html
create mode 100644 doc/help/api-ppd.html
create mode 100644 doc/help/classes-conf-reference.html
create mode 100644 doc/help/client-conf-reference.html
create mode 100644 doc/help/cupsd-conf-reference.html
create mode 100644 doc/help/error_log-reference.html
create mode 100644 doc/help/network.html
create mode 100644 doc/help/overview.html
create mode 100644 doc/help/page_log-reference.html
create mode 100644 doc/help/printers-conf-reference.html
create mode 100644 doc/help/spec-ppd.html
create mode 100644 doc/help/standard.html.in
create mode 100644 doc/help/subscriptions-conf-reference.html
create mode 100644 doc/help/whatsnew.html
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/add-this-printer.gif
create mode 100644 doc/images/bottom-left.gif
create mode 100644 doc/images/bottom-right.gif
create mode 100644 doc/images/cancel-all-jobs.gif
create mode 100644 doc/images/cancel-job.gif
create mode 100644 doc/images/cancel.gif
create mode 100644 doc/images/change-settings.gif
create mode 100644 doc/images/classes.gif
create mode 100644 doc/images/continue.gif
create mode 100644 doc/images/cups-black-button-2.2.scm
create mode 100644 doc/images/cups-block-diagram.gif
create mode 100644 doc/images/cups-green-button-2.2.scm
create mode 100644 doc/images/cups-large.gif
create mode 100644 doc/images/cups-medium.gif
create mode 100644 doc/images/cups-red-button-2.2.scm
create mode 100644 doc/images/cups-small.gif
create mode 100644 doc/images/cups-standard-button-2.2.scm
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/edit-configuration-file.gif
create mode 100644 doc/images/esp-logo.gif
create mode 100644 doc/images/happy.gif
create mode 100644 doc/images/help.gif
create mode 100644 doc/images/hold-job.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/manage-server.gif
create mode 100644 doc/images/modify-class.gif
create mode 100644 doc/images/modify-printer.gif
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/publish-printer.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/save-changes.gif
create mode 100644 doc/images/search.gif
create mode 100644 doc/images/set-allowed-users.gif
create mode 100644 doc/images/set-as-default.gif
create mode 100644 doc/images/set-printer-options.gif
create mode 100644 doc/images/show-active.gif
create mode 100644 doc/images/show-all.gif
create mode 100644 doc/images/show-ascending.gif
create mode 100644 doc/images/show-completed.gif
create mode 100644 doc/images/show-descending.gif
create mode 100644 doc/images/show-next.gif
create mode 100644 doc/images/show-previous.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/images/tab-left.gif
create mode 100644 doc/images/tab-right.gif
create mode 100644 doc/images/top-left.gif
create mode 100644 doc/images/top-middle.gif
create mode 100644 doc/images/top-right.gif
create mode 100644 doc/images/unpublish-printer.gif
create mode 100644 doc/images/use-default-config.gif
create mode 100644 doc/images/view-access-log.gif
create mode 100644 doc/images/view-error-log.gif
create mode 100644 doc/images/view-page-log.gif
create mode 100644 doc/index.html.in
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/ppd.shtml
create mode 100644 doc/printing-overview.shtml
create mode 100644 doc/references.shtml
create mode 100644 doc/robots.txt
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 doc/translation.html
create mode 100644 doc/translation.pdf
create mode 100644 doc/translation.shtml
create mode 100644 filter/Dependencies
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/gziptoany.c
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-private.h
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/interpret.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/rastertolabel.c
create mode 100644 filter/testimage.c
create mode 100644 filter/testraster.c
create mode 100644 filter/textcommon.c
create mode 100644 filter/textcommon.h
create mode 100644 filter/texttops.c
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/Makefile
create mode 100644 fonts/Symbol
create mode 100755 install-sh
create mode 100644 locale/Makefile
create mode 100644 locale/cups.footer
create mode 100644 locale/cups.header
create mode 100644 locale/cups.pot
create mode 100644 locale/cups_fr.po
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-config.man
create mode 100644 man/cups-lpd.man
create mode 100644 man/cups-polld.man
create mode 100644 man/cupsaddsmb.man
create mode 100644 man/cupsd.conf.man
create mode 100644 man/cupsd.man
create mode 100644 man/cupsenable.man
create mode 100644 man/cupstestppd.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/lppasswd.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/mantohtml.c
create mode 100644 man/mime.convs.man
create mode 100644 man/mime.types.man
create mode 100644 man/printers.conf.man
create mode 100644 notifier/Dependencies
create mode 100644 notifier/Makefile
create mode 100644 notifier/mailto.c
create mode 100644 notifier/testnotify.c
create mode 100644 packaging/LICENSE.rtf
create mode 100644 packaging/WELCOME.rtf
create mode 100644 packaging/cups-desc.plist.in
create mode 100644 packaging/cups-info.plist.in
create mode 100644 packaging/cups.list.in
create mode 100644 packaging/cups.spec.in
create mode 100644 packaging/installer.tif
create mode 100644 packaging/installer.xcf.gz
create mode 100644 pdftops/Annot.cxx
create mode 100644 pdftops/Annot.h
create mode 100644 pdftops/Array.cxx
create mode 100644 pdftops/Array.h
create mode 100644 pdftops/BuiltinFont.cxx
create mode 100644 pdftops/BuiltinFont.h
create mode 100644 pdftops/BuiltinFontTables.cxx
create mode 100644 pdftops/BuiltinFontTables.h
create mode 100644 pdftops/CMap.cxx
create mode 100644 pdftops/CMap.h
create mode 100644 pdftops/COPYING
create mode 100644 pdftops/Catalog.cxx
create mode 100644 pdftops/Catalog.h
create mode 100644 pdftops/CharCodeToUnicode.cxx
create mode 100644 pdftops/CharCodeToUnicode.h
create mode 100644 pdftops/CharTypes.h
create mode 100644 pdftops/CompactFontTables.h
create mode 100644 pdftops/Decrypt.cxx
create mode 100644 pdftops/Decrypt.h
create mode 100644 pdftops/Dependencies
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/ErrorCodes.h
create mode 100644 pdftops/FoFiBase.cxx
create mode 100644 pdftops/FoFiBase.h
create mode 100644 pdftops/FoFiEncodings.cxx
create mode 100644 pdftops/FoFiEncodings.h
create mode 100644 pdftops/FoFiTrueType.cxx
create mode 100644 pdftops/FoFiTrueType.h
create mode 100644 pdftops/FoFiType1.cxx
create mode 100644 pdftops/FoFiType1.h
create mode 100644 pdftops/FoFiType1C.cxx
create mode 100644 pdftops/FoFiType1C.h
create mode 100644 pdftops/FontEncodingTables.cxx
create mode 100644 pdftops/FontEncodingTables.h
create mode 100644 pdftops/Function.cxx
create mode 100644 pdftops/Function.h
create mode 100644 pdftops/GHash.cxx
create mode 100644 pdftops/GHash.h
create mode 100644 pdftops/GList.cxx
create mode 100644 pdftops/GList.h
create mode 100644 pdftops/GMutex.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/GlobalParams.cxx
create mode 100644 pdftops/GlobalParams.h
create mode 100644 pdftops/JArithmeticDecoder.cxx
create mode 100644 pdftops/JArithmeticDecoder.h
create mode 100644 pdftops/JBIG2Stream.cxx
create mode 100644 pdftops/JBIG2Stream.h
create mode 100644 pdftops/JPXStream.cxx
create mode 100644 pdftops/JPXStream.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/NameToCharCode.cxx
create mode 100644 pdftops/NameToCharCode.h
create mode 100644 pdftops/NameToUnicodeTable.h
create mode 100644 pdftops/Object.cxx
create mode 100644 pdftops/Object.h
create mode 100644 pdftops/Outline.cxx
create mode 100644 pdftops/Outline.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/PDFDocEncoding.cxx
create mode 100644 pdftops/PDFDocEncoding.h
create mode 100644 pdftops/PSOutputDev.cxx
create mode 100644 pdftops/PSOutputDev.h
create mode 100644 pdftops/PSTokenizer.cxx
create mode 100644 pdftops/PSTokenizer.h
create mode 100644 pdftops/Page.cxx
create mode 100644 pdftops/Page.h
create mode 100644 pdftops/Parser.cxx
create mode 100644 pdftops/Parser.h
create mode 100644 pdftops/README
create mode 100644 pdftops/SecurityHandler.cxx
create mode 100644 pdftops/SecurityHandler.h
create mode 100644 pdftops/Splash.cxx
create mode 100644 pdftops/Splash.h
create mode 100644 pdftops/SplashBitmap.cxx
create mode 100644 pdftops/SplashBitmap.h
create mode 100644 pdftops/SplashClip.cxx
create mode 100644 pdftops/SplashClip.h
create mode 100644 pdftops/SplashErrorCodes.h
create mode 100644 pdftops/SplashFTFont.cxx
create mode 100644 pdftops/SplashFTFont.h
create mode 100644 pdftops/SplashFTFontEngine.cxx
create mode 100644 pdftops/SplashFTFontEngine.h
create mode 100644 pdftops/SplashFTFontFile.cxx
create mode 100644 pdftops/SplashFTFontFile.h
create mode 100644 pdftops/SplashFont.cxx
create mode 100644 pdftops/SplashFont.h
create mode 100644 pdftops/SplashFontEngine.cxx
create mode 100644 pdftops/SplashFontEngine.h
create mode 100644 pdftops/SplashFontFile.cxx
create mode 100644 pdftops/SplashFontFile.h
create mode 100644 pdftops/SplashFontFileID.cxx
create mode 100644 pdftops/SplashFontFileID.h
create mode 100644 pdftops/SplashGlyphBitmap.h
create mode 100644 pdftops/SplashMath.h
create mode 100644 pdftops/SplashOutputDev.cxx
create mode 100644 pdftops/SplashOutputDev.h
create mode 100644 pdftops/SplashPath.cxx
create mode 100644 pdftops/SplashPath.h
create mode 100644 pdftops/SplashPattern.cxx
create mode 100644 pdftops/SplashPattern.h
create mode 100644 pdftops/SplashScreen.cxx
create mode 100644 pdftops/SplashScreen.h
create mode 100644 pdftops/SplashState.cxx
create mode 100644 pdftops/SplashState.h
create mode 100644 pdftops/SplashT1Font.cxx
create mode 100644 pdftops/SplashT1Font.h
create mode 100644 pdftops/SplashT1FontEngine.cxx
create mode 100644 pdftops/SplashT1FontEngine.h
create mode 100644 pdftops/SplashT1FontFile.cxx
create mode 100644 pdftops/SplashT1FontFile.h
create mode 100644 pdftops/SplashTypes.h
create mode 100644 pdftops/SplashXPath.cxx
create mode 100644 pdftops/SplashXPath.h
create mode 100644 pdftops/SplashXPathScanner.cxx
create mode 100644 pdftops/SplashXPathScanner.h
create mode 100644 pdftops/Stream-CCITT.h
create mode 100644 pdftops/Stream.cxx
create mode 100644 pdftops/Stream.h
create mode 100644 pdftops/UTF8.h
create mode 100644 pdftops/UnicodeMap.cxx
create mode 100644 pdftops/UnicodeMap.h
create mode 100644 pdftops/UnicodeMapTables.h
create mode 100644 pdftops/UnicodeTypeTable.cxx
create mode 100644 pdftops/UnicodeTypeTable.h
create mode 100644 pdftops/XRef.cxx
create mode 100644 pdftops/XRef.h
create mode 100644 pdftops/XpdfPluginAPI.cxx
create mode 100644 pdftops/XpdfPluginAPI.h
create mode 100644 pdftops/config.h
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/dymo.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/stcolor2.ppd
create mode 100644 ppd/stphoto.ppd
create mode 100644 ppd/stphoto2.ppd
create mode 100644 ppd/zebra.ppd
create mode 100644 ppd/zebracpl.ppd
create mode 100644 ppd/zebraep1.ppd
create mode 100644 ppd/zebraep2.ppd
create mode 100644 pstoraster/README.pstoraster
create mode 100644 pstoraster/cups.mak
create mode 100644 pstoraster/gdevcups.c
create mode 100644 pstoraster/gs707-lib.patch
create mode 100644 pstoraster/gs811-lib.patch
create mode 100644 pstoraster/pstopxl
create mode 100755 pstoraster/pstopxl.in
create mode 100755 pstoraster/pstoraster
create mode 100644 pstoraster/pstoraster.convs
create mode 100755 pstoraster/pstoraster.in
create mode 100644 pstoraster/pxlcolor.ppd
create mode 100644 pstoraster/pxlmono.ppd
create mode 100644 scheduler/Dependencies
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-deviced.c
create mode 100644 scheduler/cups-driverd.c
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.h
create mode 100644 scheduler/dirsvc.c
create mode 100644 scheduler/dirsvc.h
create mode 100644 scheduler/env.c
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/network.c
create mode 100644 scheduler/network.h
create mode 100644 scheduler/policy.c
create mode 100644 scheduler/policy.h
create mode 100644 scheduler/printers.c
create mode 100644 scheduler/printers.h
create mode 100644 scheduler/process.c
create mode 100644 scheduler/quotas.c
create mode 100644 scheduler/server.c
create mode 100644 scheduler/statbuf.c
create mode 100644 scheduler/statbuf.h
create mode 100644 scheduler/subscriptions.c
create mode 100644 scheduler/subscriptions.h
create mode 100644 scheduler/testdirsvc.c
create mode 100644 scheduler/testmime.c
create mode 100644 scheduler/testspeed.c
create mode 100644 scheduler/type.c
create mode 100644 scheduler/util.c
create mode 100644 scheduler/util.h
create mode 100644 scripting/java/CUPSPrinter.java
create mode 100644 scripting/java/classes/com/easysw/cups/Cups.class
create mode 100644 scripting/java/classes/com/easysw/cups/CupsJob.class
create mode 100644 scripting/java/classes/com/easysw/cups/CupsPrinter.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPP.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPAttribute.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPBase64Encoder.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPCalendar.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPDefs.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPError.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPHttp.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPMD5.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPRequest.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPStatus.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPURLConnection.class
create mode 100644 scripting/java/classes/com/easysw/cups/IPPValue.class
create mode 100644 scripting/java/cups.jar
create mode 100644 scripting/java/docs/allclasses-frame.html
create mode 100644 scripting/java/docs/com/easysw/cups/Cups.html
create mode 100644 scripting/java/docs/com/easysw/cups/CupsJob.html
create mode 100644 scripting/java/docs/com/easysw/cups/CupsPrinter.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPP.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPAttribute.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPDefs.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPError.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPHttp.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPRequest.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPStatus.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPURLConnection.html
create mode 100644 scripting/java/docs/com/easysw/cups/IPPValue.html
create mode 100644 scripting/java/docs/deprecated-list.html
create mode 100644 scripting/java/docs/help-doc.html
create mode 100644 scripting/java/docs/index-all.html
create mode 100644 scripting/java/docs/index.html
create mode 100644 scripting/java/docs/overview-tree.html
create mode 100644 scripting/java/docs/package-list
create mode 100644 scripting/java/docs/packages.html
create mode 100644 scripting/java/docs/serialized-form.html
create mode 100644 scripting/java/docs/stylesheet.css
create mode 100644 scripting/java/example/GLP.class
create mode 100644 scripting/java/example/GLP.java
create mode 100644 scripting/java/example/GLPcolors.class
create mode 100644 scripting/java/example/GLPcolors.java
create mode 100644 scripting/java/example/GLPdetail.class
create mode 100644 scripting/java/example/GLPdetail.java
create mode 100644 scripting/java/example/GLPjobList.class
create mode 100644 scripting/java/example/GLPjobList.java
create mode 100644 scripting/java/example/GLPjobTableModel.class
create mode 100644 scripting/java/example/GLPjobTableModel.java
create mode 100644 scripting/java/example/GLPoptions$1.class
create mode 100644 scripting/java/example/GLPoptions$MyTextListener.class
create mode 100644 scripting/java/example/GLPoptions.class
create mode 100644 scripting/java/example/GLPoptions.java
create mode 100644 scripting/java/example/GLPprinterDetail.class
create mode 100644 scripting/java/example/GLPprinterDetail.java
create mode 100644 scripting/java/example/GLPprinters.class
create mode 100644 scripting/java/example/GLPprinters.java
create mode 100644 scripting/java/example/GLPsearch.class
create mode 100644 scripting/java/example/GLPsearch.java
create mode 100644 scripting/java/example/GLPsearchProgressPanel$1.class
create mode 100644 scripting/java/example/GLPsearchProgressPanel$2.class
create mode 100644 scripting/java/example/GLPsearchProgressPanel$ButtonListener.class
create mode 100644 scripting/java/example/GLPsearchProgressPanel.class
create mode 100644 scripting/java/example/GLPsearchProgressPanel.java
create mode 100644 scripting/java/example/GLPserver.class
create mode 100644 scripting/java/example/GLPserver.java
create mode 100644 scripting/java/example/GLPtabs$1.class
create mode 100644 scripting/java/example/GLPtabs.class
create mode 100644 scripting/java/example/GLPtabs.java
create mode 100644 scripting/java/example/GLPvars.class
create mode 100644 scripting/java/example/GLPvars.java
create mode 100755 scripting/java/example/buildit
create mode 100644 scripting/java/example/class.list
create mode 100644 scripting/java/example/images/left.gif
create mode 100644 scripting/java/example/images/print-test-page.gif
create mode 100644 scripting/java/example/images/printer-idle.gif
create mode 100644 scripting/java/example/images/printer-stopped.gif
create mode 100644 scripting/java/example/images/restart-job.gif
create mode 100644 scripting/java/example/images/show-active.gif
create mode 100644 scripting/java/example/images/show-completed.gif
create mode 100755 scripting/java/example/runit
create mode 100644 scripting/java/src/com/easysw/cups/Cups.java
create mode 100644 scripting/java/src/com/easysw/cups/CupsJob.java
create mode 100644 scripting/java/src/com/easysw/cups/CupsPrinter.java
create mode 100644 scripting/java/src/com/easysw/cups/IPP.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPAttribute.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPBase64Encoder.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPCalendar.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPDefs.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPError.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPHttp.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPMD5.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPRequest.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPStatus.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPURLConnection.java
create mode 100644 scripting/java/src/com/easysw/cups/IPPValue.java
create mode 100755 scripting/java/src/com/easysw/cups/buildit
create mode 100644 scripting/java/src/com/easysw/cups/class.list
create mode 100644 scripting/java/src/com/easysw/cups/cups.nfo
create mode 100644 scripting/perl/CUPS.pm
create mode 100644 scripting/perl/CUPS.xs
create mode 100644 scripting/perl/Makefile.PL
create mode 100644 scripting/perl/README
create mode 100644 scripting/perl/test.pl
create mode 100644 scripting/php/Dependencies
create mode 100644 scripting/php/Example/phpcups.inc.php4
create mode 100644 scripting/php/Makefile
create mode 100644 scripting/php/README
create mode 100644 scripting/php/config.m4
create mode 100644 scripting/php/php_phpcups.h
create mode 100644 scripting/php/phpcups.c
create mode 100644 scripting/php/phpcups.php
create mode 100644 standards/pwg5100.1.pdf
create mode 100644 standards/pwg5100.2.pdf
create mode 100644 standards/pwg5100.3.pdf
create mode 100644 standards/pwg5100.4.pdf
create mode 100644 standards/rfc1179.txt
create mode 100644 standards/rfc1321.txt
create mode 100644 standards/rfc2222.txt
create mode 100644 standards/rfc2246.txt
create mode 100644 standards/rfc2487.txt
create mode 100644 standards/rfc2554.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 standards/rfc2965.txt
create mode 100644 standards/rfc3239.txt
create mode 100644 standards/rfc3380.txt
create mode 100644 standards/rfc3381.txt
create mode 100644 standards/rfc3382.txt
create mode 100644 standards/rfc3510.txt
create mode 100644 standards/rfc3986.txt
create mode 100644 standards/rfc3995.txt
create mode 100644 standards/rfc3996.txt
create mode 100644 standards/rfc3997.txt
create mode 100644 standards/rfc3998.txt
create mode 100644 standards/wd-ippmailto10-20050519.pdf
create mode 100644 systemv/Dependencies
create mode 100644 systemv/Makefile
create mode 100644 systemv/accept.c
create mode 100644 systemv/cancel.c
create mode 100644 systemv/cupsaddsmb.c
create mode 100644 systemv/cupstestppd.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-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/edit-config.tmpl.in
create mode 100644 templates/error.tmpl
create mode 100644 templates/header.tmpl
create mode 100644 templates/help-header.tmpl
create mode 100644 templates/job-cancel.tmpl
create mode 100644 templates/job-hold.tmpl
create mode 100644 templates/job-op.tmpl
create mode 100644 templates/job-release.tmpl
create mode 100644 templates/job-restart.tmpl
create mode 100644 templates/jobs-header.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-conflict.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/page.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-default.tmpl
create mode 100644 templates/printer-deleted.tmpl
create mode 100644 templates/printer-modified.tmpl
create mode 100644 templates/printer-purge.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/restart.tmpl
create mode 100644 templates/search.tmpl
create mode 100644 templates/set-printer-options-header.tmpl
create mode 100644 templates/set-printer-options-trailer.tmpl
create mode 100644 templates/test-page.tmpl
create mode 100644 templates/trailer.tmpl
create mode 100644 templates/users.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 100644 test/4.4-subscription-ops.test
create mode 100644 test/5.1-lpadmin.sh
create mode 100644 test/5.2-lpc.sh
create mode 100644 test/5.3-lpq.sh
create mode 100644 test/5.4-lpstat.sh
create mode 100644 test/5.5-lp.sh
create mode 100644 test/5.6-lpr.sh
create mode 100644 test/5.7-lprm.sh
create mode 100644 test/5.8-cancel.sh
create mode 100644 test/5.9-lpinfo.sh
create mode 100644 test/Dependencies
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 100755 tools/makesrcdist
create mode 100755 tools/testosx
create mode 100755 tools/testrpm
create mode 100644 vcnet/config.h
create mode 100644 vcnet/cups.sln
create mode 100644 vcnet/libcups2.def
create mode 100644 vcnet/libcups2.vcproj
diff --git a/CGI.txt b/CGI.txt
new file mode 100644
index 000000000..337acb891
--- /dev/null
+++ b/CGI.txt
@@ -0,0 +1,81 @@
+CGI - CUPS v1.1.21 - 06/29/2004
+-------------------------------
+
+This file describes the experimental scripting/CGI support
+provided by CUPS starting with CUPS 1.1.19.
+
+WARNING: CGI support is not complete; you may run into problems
+and limitations in the implementation of CGI in CUPS that are
+not present in full-featured web servers like Apache.
+
+
+OVERVIEW OF CGI SUPPORT IN CUPS
+
+CUPS has traditionally provided a dynamic web interface through
+four CGI programs that are executed when users open special
+directories on the CUPS server. Each CGI performs
+administration, class, job, and printer functions as directed by
+the user, but the actual programs that are run and functions
+that are available are limited to those that were originally
+designed into the scheduler.
+
+Starting with CUPS 1.1.19, support is now available for CGI
+programs and specific scripting languages, currently Java, Perl,
+PHP, and Python. The interpreters for these languages are
+currently configured at compile time. Future versions may
+expand the interface to allow for generic support of scripting
+languages similar to the Apache "AddHandler" directive, but with
+external programs instead of modules.
+
+The following MIME types are reserved for the CGI support in
+CUPS (the names have been chosen to mirror those used by
+Apache):
+
+ application/x-httpd-cgi CGI script/program
+ application/x-httpd-java Java program
+ application/x-httpd-perl Perl script
+ application/x-httpd-php PHP script
+ application/x-httpd-python Python script
+
+In order to enable the corresponding type, you must create a new
+/etc/cups/cgi.types file which maps the filename extensions to
+the appropriate MIME type, for example:
+
+ application/x-httpd-cgi cgi
+ application/x-httpd-php php
+
+CGI scripts/programs (application/x-httpd-cgi) also must have
+execution permissions to be treated as a CGI script or program.
+
+
+LIMITATIONS
+
+CUPS implements most of the CGI/1.1 specification, with the
+following limitations:
+
+ - No Location: redirection support.
+ - No PATH_INFO or PATH_TRANSLATED support.
+ - Limited HTTP field support; only the Content-Length
+ (CONTENT_LENGTH), Cookie (HTTP_COOKIE), and User-Agent
+ (HTTP_USER_AGENT) fields are placed in environment
+ variables at this time.
+
+
+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/CHANGES-1.0.txt b/CHANGES-1.0.txt
new file mode 100644
index 000000000..296d89f79
--- /dev/null
+++ b/CHANGES-1.0.txt
@@ -0,0 +1,217 @@
+CHANGES-1.0.txt
+---------------
+
+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/CHANGES-1.1.txt b/CHANGES-1.1.txt
new file mode 100644
index 000000000..c641e794a
--- /dev/null
+++ b/CHANGES-1.1.txt
@@ -0,0 +1,3462 @@
+CHANGES-1.1.txt
+---------------
+
+CHANGES IN CUPS V1.1.23
+
+ - Updated the Spanish man pages (STR #1041)
+ - The lpstat man page contained a typo (STR #1040)
+ - The scheduler's is_path_absolute() code could cause a
+ DoS (STR #1042)
+ - The scheduler's device loading code used the wrong
+ size limits for the make/model and info parameters
+ (STR #1035)
+ - The PNG loading code did not use a "long unsigned
+ integer" format specifier for the width and height
+ (STR #1032)
+ - The web interface only showed the first 4 or 8
+ characters of "{variable-name}" for undefined template
+ variables (STR #1031)
+ - The hpgltops filter did not handle a common PCL
+ command to enter HP-GL/2 mode (STR #1037)
+
+
+CHANGES IN CUPS V1.1.23rc1
+
+ - The lpr man page did not document the "-U" option (STR
+ #998)
+ - The scheduler no longer sends the page-set option when
+ printing banner pages (STR #995)
+ - Fixed a debug message in the imagetops filter (STR
+ #1012)
+ - The lprm man page listed the "-" option in the wrong
+ order (STR #911)
+ - The hpgltops filter contained two buffer overflows
+ that could potentially allow remote access to the "lp"
+ account (STR #1024)
+ - The lppasswd command did not protect against file
+ descriptor or ulimit attacks (STR #1023)
+ - The "lpc status" command used the wrong resource path
+ when querying the list of printers and jobs, causing
+ unnecessary authentication requests (STR #1018)
+ - The httpWait() function did not handle signal
+ interruptions (STR #1020)
+ - The USB backend used the wrong size status variable
+ when checking the printer status (STR #1017)
+ - The scheduler did not delete classes from other
+ classes or implicit classes, which could cause a crash
+ (STR #1015)
+ - The IPP backend now logs the remote print job ID at
+ log level NOTICE instead of INFO (so it shows up in
+ the error_log file...)
+
+
+CHANGES IN CUPS V1.1.22
+
+ - The lpstat man page incorrectly listed the "-s" option
+ as using the equivalent of the "-p" option to list the
+ printers; it uses the "-v" option to list the printers
+ (STR #986)
+ - Now allow 0-length reads in the CUPS file API (STR
+ #985)
+ - cupsDoFileRequest() now sets cupsLastError() to
+ IPP_ERROR on network errors (STR #953)
+ - The pdftops filter didn't scale small pages up to the
+ output page size when the fitplot option was used (STR
+ #984)
+ - Fixed the ipptest program usage message (STR #959)
+ - Added Spanish man pages (STR #963)
+ - Fixed the order of comparisons in the client.conf
+ reading code (STR #971)
+ - cupsLangGet() incorrectly set the current locale (STR
+ #970)
+
+
+CHANGES IN CUPS V1.1.22rc2
+
+ - The pdftops filter didn't check the range of all
+ integer attributes (STR #972)
+ - Documentation corrections (STR #944, STR #946)
+ - Also sanitize device URI in argv[0] (STR #933)
+ - cupsRasterReadHeader() didn't swap bytes for the
+ numeric fields properly (STR #930)
+
+
+CHANGES IN CUPS V1.1.22rc1
+
+ - Now sanitize the device URI that is reported in the
+ error_log file (STR #920)
+ - Fixed some memory and file descriptor leaks in the job
+ dispatch code (STR #921)
+ - Deleting a printer could cause a crash with browsing
+ enabled (STR #865, STR #881, STR #928)
+ - Browsing would turn off if the scheduler got an EAGAIN
+ error (STR #924)
+ - The mime.types file didn't recognize PostScript as a
+ PJL language name (STR #925)
+
+
+CHANGES IN CUPS V1.1.21
+
+ - The scheduler did not separate Digest authentication
+ parameters with commas (STR #882)
+ - Fixed some problems with image printing to custom page
+ sizes (STR #891)
+ - Removed the remaining scheduler code that did not use
+ the "close-on-exec" file descriptor flag to speed up
+ program invocations (STR #890)
+ - The "lpr -r" command removed the print file even if it
+ was not printed. It now only removes the file if the
+ job is successfully created (STR #886)
+ - Revamped the custom page size orientation fix (STR
+ #127)
+ - The lp, lpq, lpr, and lpstat commands now report when
+ an environment variable is pointing to a non-existent
+ printer instead of just saying "no default
+ destination" (STR #879)
+ - Queue names with 2 periods (e.g. "printer..2") were
+ not supported (STR #866)
+
+
+CHANGES IN CUPS V1.1.21rc2
+
+ - Fixed a denial-of-service bug in the CUPS browse
+ protocol support (STR #863)
+ - The scheduler used a select() timeout of INT_MAX
+ seconds when there was nothing to do, which doesn't
+ work on IRIX (STR #864)
+ - Updated the cupsaddsmb program to use the new Windows
+ 2000 PostScript drivers instead of the Windows NT
+ printer drivers (STR #390)
+ - The gziptoany filter did not produce copies for raw
+ print jobs (STR #808)
+ - The cupsLangGet() function now uses nl_langinfo(),
+ when available, to get the current encoding (STR #856)
+ - Added a ReloadTimeout directive to control how long
+ the scheduler waits for jobs to complete before
+ restarting the scheduler (STR #861)
+ - Added a note to the default cupsd.conf file which
+ mentions that you must allow connections from
+ localhost for the command-line and web interfaces to
+ work (STR #850)
+ - The IPP backend incorrectly used the local port when
+ communicating with a remote server; this caused
+ problems with some custom configurations (STR #852)
+ - The cups-lpd mini-daemon wasn't using the right
+ default banner option (STR #851)
+ - Updated the new httpDecode64_2() and httpEncode64_2()
+ functions to handle arbitrary binary data, not just
+ text (STR #860)
+ - String options with quotes in their values were not
+ quoted properly by the scheduler (STR #839)
+ - Configure script changes for GNU/Hurd (STR #838)
+ - The lppasswd program was not installed properly by GNU
+ install when the installer was not root (STR #836)
+ - Updated the cups-lpd man page (STR #843)
+ - Fixed a typo in the cupsd man page (STR #833)
+ - The USB backend now defaults to using the newer
+ /dev/usb/lpN filenames; this helps on systems which
+ use the devfs filesystem type on Linux (STR #818)
+ - The config.h file did not define the HAVE_USERSEC_H
+ constant when the configure script detected the
+ usersec.h header file. This caused authentication
+ errors on AIX (STR #832)
+ - The lp and lpr commands now report the temporary
+ filename and error if they are unable to create a
+ temporary file (STR #812)
+ - Added ServerTokens directive to control the Server
+ header in HTTP responses (STR #792)
+ - Added new httpDecode64_2(), httpEncode64_2(), and
+ httpSeparate2() functions which offer buffer size
+ arguments (STR #797)
+ - The cupsGetFile() and cupsPutFile() code did not
+ support CDSA or GNUTLS (STR #794)
+ - The httpSeparate() function did not decode all
+ character escapes (STR #795)
+ - The cupstestppd program now checks for invalid Duplex
+ option choices and fails PPD files that use
+ non-standard values (STR #791)
+ - Updated the printer name error message to indicate
+ that spaces are not allowed (STR #675)
+ - The scheduler didn't handle HTTP GET form data
+ properly (STR #744)
+ - The pstops filter now makes sure that the prolog code
+ is sent before the setup code (STR #776)
+ - The pstops filter now handles print files that
+ incorrectly start @PJL commands without a language
+ escape (STR #734)
+ - Miscellaneous build fixes for NetBSD (STR #788)
+ - Added support for quoted system group names (STR #784)
+ - Added "version" option to IPP backend to workaround
+ serious bug in Linksys's IPP implementation (STR #767)
+ - Added Spanish translation of web interface (STR #772,
+ STR #802)
+ - The LPD backend now uses geteuid() instead of getuid()
+ when it is available (STR #752)
+ - The IPP backend did not report the printer state if
+ the wait option was set to "no" (STR #761)
+ - The printer state was not updated for "STATE: foo,bar"
+ messages (STR #745)
+ - Added new CUPS API convenience functions which accept
+ a HTTP connection to eliminate extra username/password
+ prompts. This resolves a previous authentication
+ caching issue (STR #729, STR #743)
+ - The scheduler did not correctly throttle the browse
+ broadcasts, resulting in missing printers on client
+ machines (STR #754)
+ - The scheduler did not pass the correct CUPS_ENCRYPTION
+ setting to CGI programs which caused problems on
+ systems which used non-standard encryption settings
+ (STR #773)
+ - The lpq command showed 11st, 12nd, and 13rd instead of
+ 11th, 12th, and 13th for the rank (STR #769)
+ - "make install" didn't work on some platforms due to an
+ error in the man page makefiles (STR #775)
+ - Changed some calls to snprintf() in the scheduler to
+ SetStringf() (STR #740)
+
+
+CHANGES IN CUPS V1.1.21rc1
+
+ - Fixed some "type-punned" warnings produced by GCC when
+ -fstrict-aliasing is specified (STR #679)
+ - The PDF filter incorrectly calculated the bounding box
+ of a page (STR #682)
+ - The IPP backend did not use SSL when printing over a
+ port other than 443 (STR #730)
+ - The scheduler could crash when processing a Limit or
+ LimitExcept directive (STR #728)
+ - The lpq, lpr, and lp commands did not differentiate
+ between the server being unresponsive and the lack of
+ a default printer (STR #728)
+ - The PAM checks in the configure script did not stop
+ after the first match (STR #728)
+ - The cups-config man page was incorrectly placed in
+ section 3 (STR #728)
+ - The cupstestppd utility did not show a warning message
+ when a PPD file indicated BCP protocol support with
+ PJL (STR #720)
+ - The scheduler did not return the correct exit code
+ when startup failed (STR #718)
+ - The cupsRasterReadPixels() function checked for
+ EAGAIN, which caused problems on FreeBSD (STR #723)
+ - The cupsGetDests() function did not use the current
+ encryption setting (STR #653)
+ - The scheduler did not properly parse name-based
+ BrowseRelay directives in the cupsd.conf file (STR
+ #711)
+ - The IPP backend now supports the following options in
+ the device URI: encryption, waitjob, and waitprinter
+ (STR #699)
+ - The parallel, serial, socket, and USB backends did not
+ return a non-zero exit status when a job failed to
+ print in the middle of sending it (STR #715)
+ - Location directives in the cupsd.conf file were
+ case-sensitive for printer and class names, so
+ queue-specific access control was not reliable (STR
+ #700)
+ - cupsDoFileRequest() did not handle HTTP continue
+ status messages in all cases, causing sporatic
+ problems with IPP printers from some vendors (STR
+ #716)
+ - The rastertodymo driver now supports the Zebra ZPL
+ language (STR #713)
+ - The test suite no longer generates a printcap file,
+ which caused problems when testing as the root user
+ (STR #693)
+ - The scheduler now updates the accepting state of an
+ implicit class based upon the accepting state of its
+ member printers (STR #697)
+ - The pstops filter didn't properly skip leading PJL
+ commands (STR #664)
+ - The reinterpret_cast keyword was not highlighted when
+ printing C/C++ source files in prettyprint mode (STR
+ #694)
+ - Fixed a segfault problem with some of the client
+ programs (STR #668)
+ - When using RunAsUser, the scheduler did not correctly
+ set the ownership of the log files, preventing log
+ file rotation (STR #686)
+ - The image filters did not correctly load 1-bit PNG
+ files (STR #687)
+ - The pdftops filter did not show all annotation objects
+ in a PDF file (STR #674)
+ - The pdftops filter did not print the contents of
+ textual form elements, making it impossible to print a
+ filled-in form (STR #663)
+ - Integrated the MacOS X/Darwin USB backend into the
+ CUPS baseline (STR #661)
+ - The USB backend incorrectly reported "media tray
+ empty" (STR #660)
+ - The scheduler did not use a case-insensitive
+ comparison when checking for group membership, which
+ caused problems with Win9x clients printing via SAMBA
+ (STR #647)
+ - The scheduler did not report the addresses associated
+ with certain network errors, making troubleshooting
+ difficult (STR #648, #649)
+ - The cupstestppd program did not allow a default choice
+ of "Unknown" as required by the PPD spec (STR #651)
+ - The select() buffers are now allocated to be at least
+ as large as sizeof(fd_set) (STR #639)
+ - The LPD backend now supports overriding the print job
+ username via the device URI (STR #631)
+ - The scheduler did not handle an unknown MIME type when
+ checking for a CGI script (STR #603)
+ - Added a timeout optimization to the scheduler's main
+ loop to allow CUPS to sleep more of the time (STR
+ #629)
+ - The USB backend now retries printing to devices of the
+ form "usb://make/model" if any USB port shows up as
+ "busy" (STR #617)
+ - The httpGetHostByName() function did not range check
+ IP address values (STR #608)
+ - The httpUpdate() function could return HTTP_ERROR
+ instead of the HTTP status if the server closed the
+ connection before the client received the whole
+ response (STR #611)
+ - The LPD mini-daemon did not allow the administrator to
+ force banner pages on (STR #605)
+ - Added PAM support for Darwin/MacOS X (STR #550)
+ - The web interface now provides a "Set As Default"
+ button to set the default printer or class on a server
+ (STR #577)
+ - The HTTP authentication cache was broken (STR #517)
+ - The cupstestppd utility now fails PPD files that have
+ a DefaultOption keyword for a non-existance option
+ name (STR #476)
+ - Optimized the scanning of new PPD files on scheduler
+ startup (STR #424)
+ - The EPM list file did not include the bin, lib, or
+ sbin directories (STR #598)
+ - The web interface did not redirect administration
+ tasks to the primary server for a class or printer
+ (STR #491, #652)
+ - The cups-lpd mini-daemon did not reject print jobs to
+ queues that were rejecting new print jobs (STR #515)
+ - Some calls to the ctype functions did not account for
+ platforms that use a signed char type by default (STR
+ #518)
+ - The scheduler could use excess amounts of CPU if a CGI
+ program was sending data faster than the client could
+ take it (STR #595)
+ - Updated the Ghostscript 8.x integration stuff (STR
+ #484)
+ - The lpd backend used a source port of 732 by default,
+ which is outside of the range defined by RFC 1179;
+ also added a new (default) "reserve=any" option for
+ any priviledged port from 1 to 1023 (STR #474)
+ - The scheduler did not check for a valid Listen/Port
+ configuration (STR #499)
+ - The cupsPrintFiles() function did not always set the
+ last IPP error message (STR #538)
+ - The pstops filter did not write the PostScript header
+ line if the file began with a PJL escape sequence (STR
+ #574)
+ - The printer-is-accepting-jobs status of remote
+ printers was not sent to clients via browsing or
+ polling (STR #571)
+ - Browse packets did not indicate whether a printer
+ was accepting or rejecting jobs.
+ - The web interface did not show the printer state
+ history information (STR #592)
+ - The rastertoepson filter would crash under certain
+ cirsumstances (STR #583)
+ - The USB backend did not handle serial numbers using
+ the (incorrect) SN keyword and did not terminate the
+ make and model name strings properly (STR #471, STR
+ #588)
+ - The USB backend did not build on Solaris x86 (STR
+ #585)
+ - The cupsDoAuthentication() function did not use the
+ method name for Digest authentication (STR #584)
+ - The scheduler could crash if a print job could not be
+ printed and the PreserveJobHistory option was turned
+ off (STR #535)
+ - cups-lpd now logs the temporary filenames that could
+ not be opened in order to make troubleshooting easier
+ (STR #565)
+ - cupsGetJobs() now returns -1 on error (STR #569)
+ - Added localization for Belarusian (STR #575)
+ - The LPD backend used the full length of the hostname
+ when creating the data and control filenames, which
+ causes problems with older systems that can't handle
+ long filenames (STR #560)
+ - The scheduler did not refresh the common printer data
+ after a fast reload; this prevented banner and other
+ information from being updated (STR #562)
+ - The scheduler did not send common or history data to
+ the client when processing a CUPS-Get-Default request
+ (STR #559)
+ - The httpFlush() function did not always flush the
+ remaining response data in requests (STR #558)
+ - The scheduler could complete a job before it collected
+ the exit status from all filters and the backend (STR
+ #448)
+ - The PPD conformance tests did not catch group
+ translation strings that exceeded the maximum allowed
+ size (STR #454)
+ - Updated the client code in the scheduler to close the
+ client connection on errors rather than shutting down
+ the receive end of the socket; this caused resource
+ problems on some systems (STR #434)
+ - cups-polld didn't compile on Tru64 5.1B (STR #436)
+ - "lpc stat" crashed if the device URI was empty (STR
+ #548)
+ - The scheduler did not compile without zlib (STR #433)
+ - std:floor() cast needed on IRIX 6.5 with SGI C++
+ compiler (STR #497)
+ - cupsRasterReadPixels() and cupsRasterWritePixels() did
+ not handle EAGAIN and EINTR properly (STR #473)
+ - RequiresPageRegion should not be consulted for Manual
+ Feed (STR #514)
+ - International characters were not substituted in
+ banner files properly (STR #468)
+ - Updated pdftops to Xpdf 2.03 code to fix printing bugs
+ (STR #470)
+ - The Digest authentication code did not include the
+ (required) "uri" attribute in the Authorization
+ response, preventing interoperation with Apache
+ (STR #408)
+ - The web interface could lockup when displaying certain
+ URLs (STR #459)
+ - The PostScript filters now convert underscores ("_")
+ to spaces for custom classification names (STR #555)
+
+
+CHANGES IN CUPS V1.1.20
+
+ - The pstops filter didn't properly handle collated,
+ duplexed copies of documents with an odd number of
+ pages on printers that did not do their own collated
+ copies (STR #389)
+ - Tru64 doesn't define a prototype for hstrerror() (STR
+ #430)
+ - Updated the pdftops filter to use the annotation flags
+ instead of the subtype to determine whether to print
+ an annotation (STR #425)
+ - The French web interface localization did not use
+ absolute paths for the navigation bar (STR #428)
+ - The CUPS test suite did not undefine the PRINTER and
+ LPDEST environment variables. This could lead to bogus
+ test results (STR #380)
+ - The cupsLangDefault() function now works if you don't
+ have the base OS localization installed (STR #418)
+ - The pdftops filter no longer needs to create temporary
+ files with tmpnam (STR #406)
+ - The HTTP code did not use a case-insensitive
+ comparison when checking for the Basic authentication
+ method (STR #407)
+ - The httpEncode() function always added a trailing "="
+ character, which is not required by the Base64
+ encoding specification (STR #407)
+ - The signal handlers did not need to call sigset();
+ this caused a recursion problem on some versions of
+ IRIX (STR #422)
+ - Moved the scheduler termination code into the mainline
+ to be consistent with the way other signals are
+ handled (STR #423)
+ - The cupsaddsmb program didn't export the new CUPS
+ driver for Windows properly (STR #390)
+ - The ppdOpen() functions did not issue an error when a
+ translation string exceeded the maximum allowed by the
+ Adobe PPD specification (STR #399)
+ - The default landscape orientation was not the same as
+ that defined in the PPD file (STR #397)
+ - Updated the pstoraster patch files and CUPS driver to
+ work with Ghostscript 8 (STR #402)
+ - The hpgltops filter did not skip PJL commands (STR
+ #379)
+
+
+CHANGES IN CUPS V1.1.20rc6
+
+ - "lp -i jobid -H restart" would often return an error
+ even though the job restarted successfully (STR #362)
+ - The scheduler did not check for invalid allow/deny
+ addresses such as "11.22.33.44/24". It now masks off
+ the extra address bits and logs a warning message in
+ the error_log file (STR #337)
+ - The cupstestppd utility now checks for missing
+ ImageableArea and PaperDimension attributes for each
+ defined PageSize (STR #365)
+ - The IPP code did not wait for a reply indefinitely on
+ HTTP connections in "blocking" mode (STR #377)
+ - The web interfaces did not rewrite the default printer
+ URI properly (STR #299 and #369)
+ - The LPD backend passed the C and L commands in the
+ wrong order (STR #378)
+ - The Dymo label printer driver did not set the label
+ length properly (STR #373)
+ - The scheduler did not support job IDs higher than
+ 99999 (STR #371)
+ - The Visual C++ project files did not work (STR #366)
+ - The scheduler's cupsLangSeek() function did not reset
+ the "EOF" flag, preventing compressed files from being
+ typed properly in some cases (STR #368)
+ - The cupsLangGet() cache was only used if the locale
+ name provided an explicit character set name (STR
+ #354)
+ - The CUPS API convenience functions did not call
+ cupsLangFree() when they were done with the
+ localization data (STR #354)
+ - The scheduler did not return the
+ job-hold-until-supported or job-hold-until-default
+ attributes (STR #356)
+ - The cupsaddsmb program did not support the new CUPS
+ driver for Windows (STR #357)
+
+
+CHANGES IN CUPS V1.1.20rc5
+
+ - The scheduler did not initialize the browse socket
+ file descriptor properly when only SLP browsing was
+ enabled (STR #259)
+ - The scheduler accessed the job attributes before they
+ were set (STR #347, fix to STR #335)
+ - The cupsCancelJob() function did not return 0 when the
+ job could not be canceled (STR #340)
+
+
+CHANGES IN CUPS V1.1.20rc4
+
+ - The scheduler did not move the incoming job attributes
+ in the operation group to the job group (STR #335)
+ - The cupsDoFileRequest() function did not check for an
+ early HTTP response while sending the file (STR #314)
+ - The web interfaces did not quote #, ?, or . in printer
+ names, which caused some problems with the generated
+ URLs (STR #320)
+ - CUPS couldn't be completely compiled with the -dDEBUG
+ option (STR #331)
+
+
+CHANGES IN CUPS V1.1.20rc3
+
+ - More SLP changes (STR #259)
+ - Revamped the child signal handling code to completely
+ avoid deadlock issues on Solaris (STR #325)
+ - The lpadmin command displayed an incorrect error
+ message when the "-u" option was provided with no
+ arguments (STR #313)
+ - The web admin interface did not display an error
+ message if the PPD file could not be loaded (STR #308)
+ - The ppdEmit() functions did not use the correct
+ orientation value position for custom page sizes (STR
+ #292)
+
+
+CHANGES IN CUPS V1.1.20rc2
+
+ - The serial backend set the IXANY option on the port
+ for XON/XOFF flow control; this caused problems with
+ printers that returned status info but were not ready
+ for more print data (STR #287)
+ - The scheduler didn't support scripted index files
+ (index.php, index.pl, etc. - STR #290)
+ - The scheduler did not correctly localize script files
+ with "GET" variables (STR #268)
+ - Changes in job classification are now logged (STR
+ #289)
+ - Fixed a few more SLP-related bugs (STR #259)
+ - Updated the user/group configure checks for MacOS X
+ 10.3 (STR #270)
+ - Fixed an offset bug in the PDF filter (STR #284)
+ - The cupsDoRequest() and cupsDoFileRequest() functions
+ did not map several HTTP status codes to their IPP
+ counterparts. This made detecting certain conditions
+ very difficult (STR #277)
+ - Config, spool, and status files are now owned by the
+ scheduler user (usually root) with read permission for
+ the filter group (STR #283)
+ - The HP-GL/2 filter did not support the SI command,
+ some values for the AD and SD commands, and did not
+ rotate labels properly via the DI command (STR #282)
+ - The fax support did not update/set the job-hold-until
+ attribute when a fax job fails (STR #269)
+ - The cupsLangGet() function didn't support locales of
+ the form "ll.charset" (STR #271)
+ - The scheduler did not use the charset when getting the
+ language localization for a request; this caused extra
+ disk IO for every request (STR #271)
+ - The scheduler did not support requests with more than
+ one language specified (STR #267)
+
+
+CHANGES IN CUPS V1.1.20rc1
+
+ - The scheduler now waits up to 60 seconds before
+ restarting to allow active jobs to complete printing
+ and pending requests to be processed (STR #226)
+ - The web interface did not work on systems where time_t
+ is 64 bits (STR #262)
+ - Added backend tweeks and content-length check from Red
+ Hat (STR #253)
+ - The USB backend now uses the 8255 constants instead of
+ the standard constants when reporting printer status
+ bits on Linux (STR #254)
+ - Added new cupsDoAuthentication(), cupsGetFd(),
+ cupsGetFile(), cupsPutFd(), and cupsPutFile() functions
+ to the CUPS API (STR #112)
+ - The PDF filter always scaled and offset pages; this
+ caused problems under MacOS X, so now the "fitplot"
+ option controls whether PDF files are scaled to fit
+ within the printable area of the page (STR #250)
+ - The LPD backend did not support the port number in a
+ URI (STR #247)
+ - Some filters didn't properly support boolean options
+ (STR #249)
+ - Landscape PDF files were not always offset by the
+ correct amount when rotating (STR #243)
+ - The scheduler could hang in a call to localtime() when
+ logging messages from the signal handler (STR #242)
+ - The PDF filter no longer prints form widgets; this
+ duplicates the behavior of Acrobat Reader (STR #241)
+ - cupsGetPPD() didn't handle a late termination of a
+ HTTP connection with the server (STR #220)
+ - ppdOpen() did not correctly check for "*PPD-Adobe-4."
+ on the first line of a PPD file. This caused incorrect
+ PASS results for some PPD files (STR #233)
+ - cupsEncodeOptions() did not allow boolean options to
+ use "yes" and "on" for true values (STR #227)
+ - The pstops filter only sent the TBCP exit sequence if
+ it was defined in the JCLEnd attribute in the PPD file
+ (STR #224)
+ - Support for more than 1024 files was broken on Solaris
+ 9 (STR #217)
+ - The setgroups() calls now pass in 1 group (the
+ configured group) instead of 0 for compatibility with
+ BSD and Darwin (STR #213)
+ - The scheduler's built-in broadcast throttling was
+ ineffective since incoming packets would cause the
+ next group of outgoing packets to be sent immediately
+ rather than waiting for the next time slot (STR #211)
+ - Added a new ppdSetConformance() function to set the
+ conformance requirements for PPD files. Currently only
+ two levels are defined, PPD_CONFORM_RELAXED and
+ PPD_CONFORM_STRICT, and the default is the relaxed
+ level (STR #212)
+ - The IPP backend did not correctly execute the
+ pictwpstops filter on OSX (STR #210)
+ - The LPD backend did not set the banner class when the
+ "banner=yes" option was specified in the device URI
+ (STR #209)
+ - The imagetoraster filter did not support all of the
+ page device attributes (STR #208)
+ - The pdftops filter incorrectly auto-rotated pages when
+ the user already had specified the proper orientation
+ (STR #207)
+ - Fixed AIX shared library support (STR #201)
+ - Added support for live testing with Valgrind (STR
+ #193)
+ - The CGI programs now collect the list of needed
+ attributes for the class, job, and printer template
+ files (STR #192)
+ - The scheduler now passes the first port that is bound
+ to the local loopback or "any" addresses to the CGI
+ programs rather than the port that the browser
+ connected to (STR #103)
+ - The cupstestppd program now checks for bad
+ JobPatchFile attributes and incorrect versions of the
+ Manufacturer attribute for HP printers (STR #155)
+ - The filter makefile incorrectly installed
+ libcupsimage.a in the filter directory (STR #180)
+ - The scheduler did not verify that the job history
+ files define the job-priority and
+ job-originating-user-name attributes (STR #178)
+ - The pstops filter didn't handle poorly-formed binary
+ PostScript files that had CTRL-D's in them (STR #156)
+ - The ppdOpen*() and cupsLangGet() functions did not
+ make a copy of the old locale strings when using the
+ POSIX locale when reading files, which apparently
+ caused problems with some implementations of the
+ standard C library. (STR #159)
+ - The pdftops filter did not work properly with some
+ embedded Type1C fonts (STR #177)
+ - Updated the pdftops filter to be based upon Xpdf
+ 2.02pl1 (STR #191)
+ - The scheduler did not reset the group list when
+ running CGI and filter processes (STR #185)
+ - The scheduler no longer calls malloc and free from the
+ signal handlers (STR #190)
+ - The USB backend now uses the manufacturer and model
+ strings if the description string is not available
+ (STR #174)
+ - The ppdOpen functions still supported the
+ VariablePaperSize attribute, which was removed in v4.0
+ of the PPD spec. This caused problems with PPD files
+ that relocated the PageSize option to a non-standard
+ group (STR #158)
+ - The cups.list file referenced MAN1EXT, MAN3EXT, and
+ MAN5EXT, but none of those were actually defined (STR
+ #147)
+ - Chunked requests could cause a Denial of Service if
+ the connection is terminated before the first byte of
+ chunk data is sent/received (STR #143)
+ - Printers with special characters in their names were
+ not accessible from the web interface (STR #120)
+ - The lpstat command now shows the correct interface
+ script or PPD file, if any, for a print queue (STR #89)
+ - The lpstat command now shows the printer-state-message
+ and printer-state-reasons attributes whenever they are
+ not blank (STR #152)
+ - The French and German option-conflict.tmpl template
+ files did not get installed (STR #148)
+ - The cups.list.in file did not work when compiling
+ without shared libraries (STR #149)
+ - The DSOFLAGS included the LDFLAGS, which causes
+ problems on at least HP-UX (STR #150)
+ - The fax printer support did not keep track of the fax
+ capability bit (STR #144)
+ - The appleLangDefault() function could leak a small
+ amount of memory (STR #145)
+ - The ppdOpen() functions now mirror all normal
+ attributes to the attribute list; previously only
+ certain unassigned attributes would be added (STR
+ #139)
+ - The ppdEmitJCL() function wrote JCL commands to stdout
+ instead of the passed file pointer (STR #142)
+ - The httpGets() function could, in certain states,
+ block waiting for data (STR #132)
+ - The cupsEmitJCL() function not outputs an empty @PJL
+ command after the PJL language escape to work around
+ bugs in certain PJL implementations (STR #131)
+ - The cupsEmit*() functions didn't set the orientation
+ value properly (STR #127)
+ - The cups.spec file didn't list the rc2.d init
+ directory or the cupstestppd file (STR #134)
+
+
+CHANGES IN CUPS V1.1.19
+
+ - The GNU TLS code incorrectly used
+ gnutls_check_pending() instead of
+ gnutls_record_check_pending() (STR #128)
+ - The ppdEmit() functions output "PageSize Custom"
+ instead of "CustomPageSize True" in the DSC comments.
+ Also, the custom page size code did not use the
+ ParamCustomPageSize attributes (STR #127)
+ - The cupstestppd command did not list the conflicting
+ options (STR #123)
+ - The lpq command did not ensure that there was
+ whitespace between the fields in the job listing (STR
+ #117)
+ - The German web templates had errors (STR #119)
+ - The configure script didn't specify the static
+ libraries properly when configuring with the
+ --disable-shared option (STR #104)
+ - The cups.list file used file dependencies for package
+ formats other than portable, RPM, and Debian (STR #98)
+ - cupsLangGet() didn't use its language cache (STR #97)
+ - "lpq -P" would segfault instead of showing a usage
+ message (STR #94)
+ - Fixed compiler warnings in pdftops filter (STR #96)
+
+
+CHANGES IN CUPS V1.1.19rc5
+
+ - Jobs with banner pages that were printed to implicit
+ classes would get double banner pages for each
+ file/banner in the job (STR #68)
+ - The mime.convs file was missing the filter definition
+ for Windows BMP (image/x-bitmap) files (STR #85)
+ - The scheduler allowed some READ-ONLY job attributes to
+ be set, which could cause the scheduler to fail on the
+ next restart (STR #82)
+ - The lp and lpr commands did not report when the
+ scheduler was not responding; instead, the user would
+ incorrectly see a "no default destination" error (STR
+ #70)
+ - cupsLangGet() could fail on OSX due to a corrupt
+ language preference (STR #78)
+ - Added more checks for HTTP request timeouts.
+ - The scheduler dropped the first non-alpha character
+ after an open brace when doing attribute substitutions
+ in banner pages (STR #77)
+ - The scheduler child might send SIGUSR1 to the parent
+ before the signal handler was installed; this didn't
+ prevent the scheduler from starting but produced an
+ annoying error message (STR #45)
+
+
+CHANGES IN CUPS V1.1.19rc4
+
+ - The lp command did not accept "-" for printing from
+ the standard input as required by POSIX 1003.1 (STR
+ #59)
+ - Added the job-originating-host-name information for
+ the page_log file documentation in the SAM (STR #31)
+ - The German web interface templates did not use the
+ right paths for job operations (STR #54)
+ - The scheduler would consume all available CPU if
+ started with a pending job in the queue (STR #35)
+ - The polling daemon allocated an extra localization
+ buffer but did not free it, causing cups-polld to
+ eventually use all available memory (STR #40)
+
+
+CHANGES IN CUPS V1.1.19rc3
+
+ - The scheduler could get in an infinite loop cancelling
+ jobs using "cancel -u user dest" (STR #48)
+ - The "cancel -u user" command did nothing (it should
+ cancel all jobs on all printers owned by the named
+ user - STR #48)
+ - The scheduler would write 0-length job control files
+ (STR #46)
+ - Updated the French man pages (translation provided by
+ Gilles QUERRET)
+ - The scheduler would delete all printers from
+ printers.conf if a job was active when a HUP signal
+ was handled (STR #47)
+ - The cups-polld program would leak memory if it was
+ unable to send browse packets to the loopback
+ interface (STR #40)
+ - The scheduler did not put the
+ job-originating-host-name attribute in the job
+ attributes group.
+ - The text filter did not default to wrapping text as
+ defined by the IPP implementation document.
+ - Scan backends first, PPDs second (STR #37)
+ - Updated the Netatalk documentation in the SAM (STR #38
+ and #39)
+ - The test suite sent text files to a non-PS print queue,
+ which requires ESP Ghostscript (provided separately).
+ Now send the JPEG test file (STR #33)
+ - The test suite did not show the estimated disk space
+ requirements (STR #33)
+ - The test suite did not set the MaxLogSize directive to
+ 0 to prevent log file rotation (STR #33)
+ - The test suite still setup the old CUPS Ghostscript
+ symlinks (STR #33)
+ - The pstops filter did not report the correct number of
+ copies for the page_log file when printing collated
+ copies to a printer that doesn't support them in
+ hardware (STR #32)
+ - cupsLangGet() needs to set the CTYPE locale to "C"
+ (POSIX) to avoid erroneous tolower/toupper values (fix
+ suggested by Bjoern Jacke)
+ - Fixed a typo in the cups.list.in file.
+ - Updated all of the Western European locales to default
+ to ISO-8859-15 (for Euro support, suggested by Bjoern
+ Jacke)
+ - Updated the German message catalog (update provided by
+ Bjoern Jacke)
+
+
+CHANGES IN CUPS V1.1.19rc2
+
+ - cupsLangGet() now sets the encoding field based on the
+ trailing charset in the locale name, and doesn't look
+ for a message catalog in a specific locale.charset
+ directory. This fixes STR #26 and is more in line
+ with the CUPS 1.2 implementation.
+ - The configure script now aborts if the "ar" command or
+ compilers cannot be found.
+ - The static cupsimage library was not built by default.
+ - The path for the "ln" command was hardcoded in
+ Makedefs.in instead of being checked at configure time
+ (STR #28).
+ - Banner pages containing unescaped { characters would
+ not work.
+ - The printer-state-time collection attribute was
+ encoded as an enumeration instead of an integer.
+ - The printer-is-accepting-jobs collection attribute was
+ was not added to the collection value.
+ - The printer-state-sequence-number collection attribute
+ was not added to the collection value.
+ - Fixed typo and const mismatch in IPP backend.
+ - Updated the man pages for the new configuration
+ directives.
+ - Updated the SAM for MacOS 10.2, the CUPS drivers for
+ windows, the available LPD backend options, and the
+ new configuration directives.
+ - The imagetops filter didn't position images properly
+ on the page (STR #18)
+ - The configure script didn't add CPPFLAGS to the
+ compiler options or LDFLAGS to the DSO options (STR
+ #13)
+ - The scheduler would try to write a debug log message
+ when starting a job that contained a NULL string.
+ Since not all versions of snprintf() support NULL
+ string pointers this caused some problems (STR #20)
+ - The testipp program now supports reading of IPP
+ message files such as those used for the job history
+ in /var/spool/cups.
+
+
+CHANGES IN CUPS V1.1.19rc1
+
+ - Added CUPS support files for Java, Perl, and PHP
+ (located in the "scripting" subdirectory...)
+ - The scheduler now supports fast-reloads of the
+ cupsd.conf file when it is updated via HTTP.
+ - The scheduler always changed the ownership of log
+ files; it now only does so if they are not in the /dev
+ directory (i.e. don't want to change the ownership and
+ permissions of /dev/null...)
+ - Added libpaper support (patch from Jeff Licquia)
+ - Added a new istring() rule for MIME types files that
+ does a case-insensitive comparison of strings.
+ - The cups-lpd mini-daemon now sends jobs to the default
+ queue when an empty queue name (or "lp" and there is
+ no "lp" queue) is sent.
+ - The scheduler now supports fax queues identified by a
+ "*cupsFax: True" attribute in the PPD file. When a job
+ can't be sent, it is held for 5 minutes by default
+ while other jobs are attempted. The FaxRetryLimit and
+ FaxRetryInterval directives control the number of
+ retries and the time between retries.
+ - The scheduler now preserves the default options of PPD
+ files when modifying/upgrading an existing PPD file.
+ When installing a new printer, the scheduler sets the
+ default media size to Letter or A4 as appropriate for
+ your locale.
+ - The scheduler no longer limits the number of
+ BrowseAddress, BrowsePoll, BrowseRelay, Listen, Port,
+ SSLListen, and SSLPort directives to 10.
+ - The scheduler now supports print files that have been
+ compressed using gzip.
+ - The scheduler used the stdio functions to read any job
+ ticket information in a PostScript print job. Since
+ some platforms limit the number of stdio files to 256,
+ job ticket information was ignored when the server had
+ a large number of clients connected to the system.
+ - Filters and backends may now report the total number
+ of pages ("PAGE: total NNN") to the scheduler.
+ - The LPD backend now supports timeout and
+ sanitize_title options (default to 300 and yes,
+ respectively) and has some additional changes to
+ reduce the chances of multiple copies being printed
+ when only one copy was requested.
+ - Fixed a polygon drawing bug in the HP-GL/2 filter.
+ - Added a robots.txt file to the standard install to
+ prevent search engines from indexing the CUPS server.
+ - Added support for STATE: messages
+ (printer-state-reasons), printer-state-history, and
+ printer-state-time to the scheduler.
+ - When using RunAsUser, the scheduler would initially
+ start any previously queued (pending) jobs with
+ RunAsUser disabled - all backends would be running as
+ root.
+ - If a backend failed for a printer, CUPS would
+ incorrectly requeue the job for printing again.
+ - Added support for IPP collections and files.
+ - Added experimental support for generic CGI scripts and
+ programs, Java, Perl, PHP, and Python to the
+ scheduler. See the file "CGI.txt" for more
+ information.
+ - The CUPS API now supports HTTP cookies and the Expect:
+ field.
+ - The cancel command now correctly supports the "-u
+ user" option to cancel all jobs for the named user.
+ - The Purge-Jobs operation now supports the my-jobs
+ boolean attribute and a new purge-jobs boolean
+ attribute to control whether job history data is
+ purged from the scheduler; the default is false for
+ my-jobs and true for purge-jobs to match the original
+ implementation.
+ - The scheduler would not timeout printers when only
+ using SLP browsing.
+ - If the scheduler was unable to execute a filter, it
+ would try to restart the job indefinitely until the
+ filter could be executed.
+ - When writing BSD printcap files, the scheduler now
+ includes the rm and rp attributes, allowing the file
+ to be exported to LPD clients. [Patch from Dominic
+ Kubla]
+ - The scheduler optimization to reference IPP attribute
+ data instead of performing a full copy caused problems
+ when the referenced data was deleted before it was
+ sent. It now only references attributes that change
+ only when the scheduler is restarted. The change also
+ reduced the memory footprint of a printer object to
+ 2k.
+ - The scheduler now holds signals while logging messages
+ to avoid potential deadlock issues when handling
+ signals on Solaris 8.
+ - The lpadmin command now allows printer access control
+ by group name as well as user name.
+ - "lpoptions -l" got in an infinite loop if no default
+ printer was available.
+ - The scheduler now logs the job-originating-host-name
+ attribute in the page_log file, and uses "-" for any
+ empty fields (patch from Dominik Kubla).
+ - The pdftops filter now scales PDF pages within the
+ printable area of the page.
+ - The pstops filter didn't include the page-label and
+ classification boxes when printing EPS or non-
+ conformant PS files.
+ - The imagetops filter didn't always correctly position
+ the image on the page when printing in landscape
+ orientation.
+ - The ppdEmit() functions now support the
+ RequiresPageRegion attribute when sending InputSlot
+ and ManualFeed commands.
+ - The PPD loading code now supports standard options
+ outside of OpenUI/CloseUI as required by the PPD spec.
+ - The cupstestppd program has been upgraded to provide a
+ concise PASS/FAIL report, additional detailed
+ conformance testing, and support for gzip'd PPD files.
+ - The PPD loading code is now much more strict when
+ loading a PPD file, and tracks more format errors.
+ - The scheduler ignored child signals when gathering the
+ list of available devices, when it should have been
+ using the default signal handler.
+ - The cupsEncodeOptions() function could encode an
+ option with a NULL last string.
+ - The socket backend could report the wrong number of
+ backchannel bytes if an error occurred on the link.
+ - The cups-polld program now only sleeps after getting
+ all printers and classes. This allows for longer
+ intervals without excessive delays before classes show
+ up...
+ - Added a new httpWait() function to support waiting for
+ data for a specific number of milliseconds.
+ - httpGets() now times out after 1 second on
+ non-blocking HTTP connections.
+ - The scheduler no longer accepts rangeOfInteger values
+ that are out of order (e.g. 5-1)
+ - The sides attribute was incorrectly sent as a name
+ value; it is a keyword value.
+ - The IPP backend now detects if the destination queue
+ has gone away and reports an error.
+ - The scheduler and HTTP API now allocate their select()
+ sets to support larger numbers of clients on systems
+ that support it.
+ - The scheduler now sets the CFProcessPath environment
+ variable under MacOS X.
+ - The cupsLangDefault() function now uses the
+ CoreFoundation localization API under MacOS X.
+ - The httpSeparate() function didn't handle file URIs of
+ the form "file:///path" properly.
+ - The lpadmin command now supports a "protocol" option
+ for specifying the binary communications protocol to
+ use when printing binary PostScript data.
+ - The scheduler did not properly parse the SystemGroup
+ directive, so only the first group would be used.
+ - Revamped how strings are stored in the scheduler,
+ providing a substantial improvement in memory usage
+ for systems with large numbers of printers.
+ - The PostScript filter now supports binary PostScript
+ files and files beginning with the PJL language escape
+ sequence.
+ - The PPD API now provides additional information from
+ the PPD file.
+ - The USB backend didn't compile on Solaris Intel.
+ - The cupstestppd utility now supports the "-q" option
+ (quiet) for use in scripts, etc.
+ - Merged several weight-reducing changes into the CUPS
+ baseline donated by Apple.
+ - Added preliminary support for CDSA; patch provided by
+ Apple.
+ - Implicit classes are now created from identical
+ printer classes on the network.
+ - The lp command now supports a "-H restart" option to
+ restart previously printed jobs. This functionality
+ only works if you have enabled the PreserveJobFiles
+ option.
+ - The scheduler now supports URIs in HTTP request lines
+ to conform to the HTTP/1.1 specification.
+ - The time-at-xyz attributes were not recognized in
+ banner files if prefixed by a question mark, e.g.
+ "{?time-at-creation}".
+ - Added support for pre-filtering application/pictwps
+ files on MacOS clients before sending them to a server
+ via IPP.
+ - The scheduler now allows file:/dev/null device URIs
+ even if FileDevices is set to No.
+ - CUPS uses strerror() for hostname resolution errors,
+ when it should have used hstrerror().
+ - The USB backend no longer tries to guess the serial
+ number of a device from the USB devices file; this
+ means that printers that don't report their serial
+ numbers in the device ID string will not be
+ individually selectable.
+ - The pstops filter didn't handle page ranges properly
+ when a page contained an embedded document.
+ - Added a translation of the web interface to German.
+ - When printing using the OutputOrder=Reverse option
+ with duplexing, the output order is now truly
+ reversed; the order of sub-pages when printing N-up is
+ the same.
+ - The pstops filter did not always output the extra
+ blank page when printing a document with an odd number
+ of pages with duplexing enabled.
+ - The ippAddXYZ functions no longer allow the
+ application to add less than 1 value.
+ - Fixed a URL rewrite bug in the web interface - local
+ access was sometimes redirected away from localhost...
+ - The ppdOpen() functions could get in an infinite loop
+ if the PPD file contained a keyword or text that was
+ too large for the buffer.
+ - Added preliminary support for GNU TLS; patch provided
+ by Jeff Licquia.
+ - Now timeout IPP attribute reads after 1 second inside
+ an attribute definition.
+ - Now timeout connections that have been shutdown (due
+ to errors) after 30 seconds instead of the Timeout
+ setting (300 seconds by default). This provides
+ faster recovery from DoS attacks.
+ - A denial-of-service attack warning message was being
+ written to the log files by the scheduler for every
+ detection. This caused a DoS of its own in some
+ situations. The warning message is now written no more
+ than once per minute.
+ - Fixed the CIE colorspace support code in the image and
+ PS RIPs.
+ - The job-quota-period, job-page-limit, and job-k-limit
+ attributes were not flagged as integers, so setting
+ quotas would not work.
+ - Added an additional response check in the scheduler to
+ more quickly recover from denial-of-service attacks.
+ - The cupstestppd file was incorrectly installed in the
+ /usr/sbin directory instead of /usr/bin.
+ - The EPM list file did not include the cupstestppd
+ program or man page files.
+
+
+CHANGES IN CUPS V1.1.18
+
+ - Fixed a bug in the Set-Job-Attributes code in the
+ scheduler that would cause it to crash or continuously
+ write a job control file.
+ - SECURITY FIX: The scheduler now provides a FileDevice
+ directive to control whether new printers can be added
+ using device URIs of the form "file:/filename". The
+ default is to not allow printers with these device
+ URIs.
+ - The scheduler did not compute the cost of filters
+ properly, nor did it choose a multi-filter solution
+ with a lower cost than a single filter solution.
+ - Now install CUPS PPD file test utility (cupstestppd)
+ to support basic conformance testing of PPD files.
+ - The scheduler now logs an error message when it sees a
+ non-conforming PPD file.
+ - Upgraded pdftops filter to Xpdf 2.01 with fixes for
+ TrueType fonts.
+ - Added a MaxClientsPerHost configuration directive to
+ provide limited protection against Denial of Service
+ attacks.
+ - SECURITY FIX: Potential underflow/overflow bug in web
+ interface.
+ - SECURITY FIX: Race condition in certificate creation.
+ - SECURITY FIX: Bad URIs in browse packets could be used
+ to exploint the web interface underflow/overflow bug.
+ - SECURITY FIX: Some types of Denial of Service attacks
+ were not handled properly, so once the attack was over
+ the scheduler did not close the connections
+ immediately on all platforms.
+ - SECURITY FIXES: Added integer overflow/underflow
+ checks for all image formats.
+ - The pstops filter didn't reset the showpage operator
+ back to its original at the end of a job; this
+ prevented the concatenation of documents (used
+ primarily for CUPS 1.2...)
+ - The cupsGetPPD() function didn't always set the
+ cupsLastError() value when an error occurred.
+ - The IPP media, output-bin, and sides attributes took
+ precedence over the corresponding PPD options, which
+ caused inconsistent behavior under MacOS X with some
+ PPD files.
+ - The cupsaddsmb utility specified the wrong number of
+ arguments to the adddriver command when adding the
+ Win9x PostScript drivers.
+ - The web interface did not always report the correct
+ error message.
+ - The scheduler did not clear the POSIX signal action
+ structure when waiting for the child to send it a
+ SIGUSR1 signal; this could cause the signal handler
+ not to be called properly, preventing the parent
+ process from returning.
+
+
+CHANGES IN CUPS V1.1.17
+
+ - The "manual_copies" option did not work when the LPD
+ backend had to retry a print job.
+ - The image filters did not convert GIF images properly.
+ - The RunAsUser option was incompatible with the new
+ daemon-mode code in 1.1.16.
+ - Fixed a problem with the Set-Job-Attributes and
+ PostScript job ticket code in the scheduler - the
+ "last" attribute pointer was never updated, which
+ could cause the scheduler to crash when applying job
+ ticket data.
+ - Fixed a problem in the scheduler that caused it to
+ continue processing HTTP requests on a connection
+ after it was shutdown.
+ - The scheduler now allows accounts authenticated via
+ PAM to not have a corresponding UNIX account, but
+ group membership still requires the account name to be
+ listed in the UNIX group file(s)...
+ - The scheduler used a fixed-size (16k) buffer for
+ encoding job options for filters; it now dynamically
+ allocates and expands the buffer as needed depending
+ on the options that are sent in a job.
+ - The pdftops filter didn't support all of the MacOS
+ characters for MacRoman encoded fonts.
+ - The cupsEncodeOptions() and cupsParseOptions()
+ functions now conform to the grammer defined by the
+ current draft of the PAPI specification. The main
+ difference is that option=yes and option=no are no
+ longer treated as boolean options.
+ - The IPP backend didn't honor the encryption settings
+ in /etc/cups/client.conf.
+ - Fixed a potential bug in the HTTP code which was
+ caused by servers sending the status line and
+ newline(s) in separate packets.
+ - User-defined classification strings are now printed
+ verbatim - previously the classification box would be
+ empty.
+ - Re-added Spanish to the list of PPD languages that
+ CUPS supports.
+ - CUPS API library user and temp file updates for
+ Windows.
+ - The image filters did not properly handle grayscale
+ printing of Sun Raster images.
+ - The scheduler never reset the NumJobs variable before
+ loading the job list (previously this only happened on
+ a full start, so the problem was never apparent...)
+ - The HTTP and IPP read/write code didn't handle EINTR
+ (interrupted system call) errors.
+ - When under high load, the scheduler could abort due to
+ the wrong errno value after a select() call. This was
+ caused by the child signal handler.
+ - Added new load tests to the test target to verify that
+ cupsd can handle hundreds of simultaneous jobs without
+ error.
+ - The Solaris USB backend now supports the new device
+ URI syntax.
+ - The ppdOpen*() functions now reset the numeric locale
+ settings while loading a PPD file.
+ - Fixed the libtool build rules.
+ - The manpage make rules didn't use $(MAKE) and
+ $(MFLAGS) for the language subdirectories.
+ - Now set the LC_TIME locale category to get the
+ properly localized time string.
+ - Fixed a problem in the scheduler that would cause the
+ web interface problems when adding, modifying, or
+ configuring a printer or class.
+ - The backends now ignore SIGPIPE so that failed job
+ filters will not stop a print queue.
+ - The lpstat command did not allow for destination lists
+ ("lpstat -v printer1,printer2")
+ - Fixed parsing of long filter status messages in the
+ scheduler.
+ - Added some startup performance enhancements to the
+ scheduler so that the printer object information is
+ regenerated fewer times and the MIME type database is
+ not filled with lots of empty filters for raw/direct
+ queues.
+ - The LPD backend now sends the job title as the print
+ filename.
+ - Added support for variable sizes in the EPSON dot
+ matrix printer drivers. This allows for pages as
+ short as 1/2" (1 row of labels) and does not do an
+ automatic form feed.
+ - French translation updates.
+ - The filters did not quote the page label string when
+ embedding it in PostScript output.
+ - The serial backend now enumerates serial ports under
+ MacOS X.
+ - The pdftops filter contained font rasterizer code that
+ wasn't being used and that depended on X11. This code
+ has been removed.
+
+
+CHANGES IN CUPS V1.1.16
+
+ - The cancel and lprm commands now both display an error
+ message and return a non-zero exit status if an
+ attempt is made to cancel a job on a non-existent
+ printer.
+ - The lpoptions command incorrectly complained if a
+ request to delete a non-existent printer was made.
+ - If the client.conf file defines an alternate server
+ name, the "configure printer" action in the web
+ interface might not work.
+ - The lpstat command now supports a "-W" option so that
+ you can display completed jobs as well as
+ not-completed (pending) jobs.
+ - The lp and lpr commands did not return an error when
+ one or more files in a set of files for printing could
+ not be printed.
+ - The lp, lpadmin, and lpstat commands now consistently
+ return with a non-zero exit status when an error
+ occurs.
+ - The scheduler would not accept print jobs sent to a
+ stopped remote printer.
+ - The texttops filter incorrectly converted the page
+ numbers in the prettyprint header to double-byte
+ characters when printing a non-Unicode text file. This
+ caused an extra space to appear between each digit in
+ the page number.
+ - The scheduler did not use a case-insensitive
+ comparison when adding filters for a printer.
+ - Upgraded the pdftops filter to Xpdf 1.01.
+ - The scheduler no longer passes the page-border and
+ number-up-layout attributes to filters when printing
+ banner pages.
+ - The LPD backend now uses a 30-second timeout when
+ sending commands and control files, and a 30-second
+ timeout when retrieving responses from an LPD server.
+ If a timeout occurs, it retries indefinitely. This
+ helps to make LPD printing over VPNs work more
+ reliably.
+ - The USB backend now supports device URIs based on the
+ printer serial number and/or model number under Linux.
+ This avoids the "wrong device filename" problem when
+ using more than one USB printer.
+ - Now just shutdown the receiving end of a client
+ connection when sending an error that requires the
+ server to disconnect from the client afterwards. This
+ fixes a problem when doing remote administration with
+ encryption enabled.
+ - The scheduler did not send a printer-state-message
+ attribute if the string was empty; it now always sends
+ this attribute. This caused the printer message to be
+ displayed for other printers in the web interface.
+ - The LPD backend now supports a "manual_copies" option,
+ e.g.: "lpd://server/queue?manual_copies=no", in order
+ to handle copies for raw jobs to printers that don't
+ implement the LPD protocol properly...
+ - The "mirror" option was not being handled by the
+ PostScript or image filters.
+ - Updated the cupsaddsmb command to support the new CUPS
+ driver for Windows NT/2k/XP.
+ - Filter status lines longer than 1023 characters could
+ cause the scheduler to get into an infinite loop.
+ - The scheduler didn't reset the job state to pending
+ when modifying an active printer.
+ - Now limit the maximum number of recursion steps when
+ searching for a filter for a job, in case a user
+ defines a circular filter rule.
+ - The PostScript filter would embed an invalid
+ requirements comment in some cases.
+ - Added support for embedded job tickets in PostScript
+ files.
+ - The PostScript filter now detects EPS files and should
+ better handle printing EPS files.
+ - The cancel command now ignores a trailing destination
+ name when cancelling a specific job ID (Solaris
+ compatibility).
+ - The scheduler now rejects jobs with copies outside the
+ range of 1 to MaxCopies, inclusive.
+ - Added new MaxCopies directive to set the maximum
+ number of copies that a user can request.
+ - The scheduler didn't block signals while it processed
+ others and when it forked processes.
+ - The scheduler checked for new jobs to print when
+ stopping a job. This caused jobs to restart before a
+ shutdown.
+ - Updated the CUPS startup script to better support
+ different timezones and to support the RedHat/Mandrake
+ init script functions, if available.
+ - The scheduler did not properly handle backslashes in
+ banner files; it incorrectly assumed that "\c" should
+ always be replaced by "c", instead of only looking for
+ "\{" and replacing it by "{".
+ - The texttops filter didn't handle prettyprint=no.
+ - The text and HP-GL/2 filters didn't check for other
+ common duplex option names like cupsMarkOptions() did.
+ - "lpoptions -x printer" no longer clears the "default
+ printer" status of the printer.
+ - cupsTempFd() now stops trying to create a temporary
+ file after 1000 tries, and aborts on any error other
+ than EEXIST. This should prevent lp/lpr hangs due to
+ a bad or missing temporary directory.
+ - The lpadmin command did not send the right URI to the
+ scheduler when setting options on classes. This
+ caused a client-error-bad-request error.
+ - The CUPS API convenience functions would attempt to
+ connect to the remote server name in a
+ "printer@server" printer name instead of dealing with
+ the default (usually local) server. Aside from
+ causing user confusion, the remote server name might
+ not be resolved properly, causing further problems.
+ - "lp -q" would cause the "lp" command to segfault, as
+ the program would try to print the option letter that
+ caused the error using the wrong index into the
+ command-line; bugfix from Debian.
+ - Fixed a minor inconsistancy in the encoding of boolean
+ attributes from printer options in
+ cupsEncodeOptions().
+ - Added a FilterNice directive which sets the priority
+ of job filter processes that are run by the scheduler.
+ - Added Solaris x86 USB printer support.
+ - The USB backend now reports both the ulpt and unlpt
+ devices under *BSD.
+ - The "lpstat -o" command would truncate the
+ "printer-jobid" string if it was longer than 21
+ characters.
+ - The PJL-based MIME type rules now look in the first
+ 1024 bytes instead of just the first 512 bytes to find
+ the language mode.
+ - The image file types are now listed explicitly in the
+ mime.convs file so that additional image file formats
+ do not use the standard CUPS image filters by default.
+ - Updated the Software Programmers Manual to include
+ all of the CUPS API functions.
+ - ppdOpen*() no longer sorts choices for an option.
+ - The web interface now enforces constraints in PPD
+ files when configuring a printer.
+ - When stopping a printer, the scheduler didn't set the
+ printer state before stopping the current job.
+ - The cupsaddsmb utility now lists all data files for
+ Win9x and WinMe clients when installing that Windows
+ driver.
+ - Jobs submitted to a class now bounce immediately to
+ the next available printer rather than waiting until
+ that printer is available.
+ - Filters and backends now also get the CLASS
+ environment variable set when a job is printed to a
+ printer class instead of a normal printer.
+ - Added French translations of the web interface, CUPS
+ Overview, Software Administrators Manual, and Software
+ Users Manual contributed by Marian REYT-LLABRES.
+ - Added several "hint" messages for common configuration
+ problems that are stored in the error_log file.
+ - httpSeparate() now unquotes %xx characters in the
+ username:password field of a URI.
+ - When starting the scheduler in daemon mode, the parent
+ process now waits for the child to signal it is ready
+ to accept connections.
+ - Added -F option to cupsd to run cupsd in the
+ foreground but detach from the controlling terminal
+ and current directory.
+ - The scheduler did not reload jobs when receiving a HUP
+ signal; this would cause problems since the pointers
+ into the file type database would no longer be valid
+ for existing jobs.
+ - The scheduler did not save the network interface list
+ update time, thus no caching of the network data was
+ actually provided.
+ - Updated the SuSE PAM configuration file.
+ - The LPD backend now supports a "reserve" option and no
+ longer reserves a priviledged port by default.
+ - The cupsaddsmb command now continues past printers
+ that do not have a PPD file to export.
+ - The lpstat command didn't treat printer names as
+ case-insensitive.
+ - The lpstat command now reports the printer location
+ attribute with "lpstat -l -p".
+ - Fixed a bug in the vsnprintf() emulation function,
+ which was used on old versions of HP-UX, IRIX, and
+ Solaris.
+ - The number-up option was incorrectly being used when
+ printing banner pages.
+ - Added support for Greek and Slovak PPD files.
+ - CUPS now supports printer names containing any
+ printable character, e.g. "123-abc", "foo-bar", etc.
+ - The null filter was not supported in mime.convs due to
+ a bug in the filter validation code.
+ - Changes in the default printer and printer attributes
+ were not always reflected in the generated printcap
+ file.
+ - Implicit classes did not inherit the location or
+ description from member printers.
+ - The httpGetHostByName() function did not handle
+ hostnames that started with a number.
+ - Updated the filters to use the %cupsRotation comment
+ instead of %%Orientation to auto-rotate pages, since
+ the use of %%Orientation is inconsistent.
+ - Added the RootCertDuration directive to control how
+ often the root authentication certificate is updated.
+ - Increased the size of the IPP write buffer to 32k to
+ allow for larger attribute values and to provide more
+ efficient output of large numbers of attributes.
+ - The polling daemon now retries the initial connection
+ to the remote server; this fixes a problem when the
+ remote server is unavailable when the scheduler starts
+ up...
+ - The scheduler didn't validate Digest users against the
+ system group(s), so Digest and BasicDigest
+ authentication didn't work for administration
+ operations.
+ - The scheduler now passes the SHLIB_PATH environment
+ variable to child processes (HP-UX shared libraries)
+ - The scheduler now maps accesses from the loopback
+ interface to "localhost".
+ - The cups-lpd mini-daemon sent a status code byte in
+ response to queue state commands, but those commands
+ only return textual data.
+
+
+CHANGES IN CUPS V1.1.15-1
+
+ - The lpc and lprm sources didn't include the CUPS
+ string function header, which is required on systems
+ that don't have their own snprintf() function.
+ - The French manpage Makefile tried to install the
+ language subdirectories when it (obviously) didn't
+ have to.
+
+
+CHANGES IN CUPS V1.1.15
+
+ - Updated the CUPS license agreement for the new MacOS
+ license exception.
+ - The printer-info attribute now defaults to the printer
+ name if no value has been set.
+ - ppdOpen() and friends now add an "Auto" InputSlot
+ option if none is provided to automatically select the
+ correct tray.
+ - Updated the ppdEmit() and ppdEmitFd() functions to
+ (re)mark the correct PageSize or PageRegion option
+ depending on the selected ManualFeed or InputSlot
+ options.
+ - ppdEmitFd() didn't handle custom page sizes.
+ - Darwin uses instead of
+ .
+ - The jobs.cgi web interface now handles all job
+ operations, allowing the administrator to allow "job
+ administrators" or operators to manage jobs (but not
+ queues) on the server.
+ - The cupsDoFileRequest() function now checks if the
+ filename passed into the function is a directory, and
+ returns the IPP_NOT_POSSIBLE error if so.
+ - New SCSI printer backend.
+ - Cleaned up handling of locales with trailing character
+ set definitions.
+ - Fixed handling of invalid PPD attributes inside
+ OpenUI/CloseUI.
+ - Fixed a problem with SSL and the job, printer, and
+ admin CGIs on ports other than 443.
+ - The scheduler didn't handle AuthClass properly.
+ - Added French translation of man pages.
+ - Updated the text filter to support the const_cast,
+ dynamic_cast, and static_cast keywords in ISO C++.
+ - Now use strlcat() and strlcpy() (or emulation
+ functions) for easier string/buffer protection.
+ - The auto-generated printcap/printers.conf files now
+ have a small comment header explaining where the file
+ comes from...
+ - The PostScript filter now supports 6, 9, and 16-up
+ output, as well as new page-border and
+ number-up-layout options.
+ - The lpoptions command didn't set options properly when
+ using the default printer.
+ - Added ConfigFilePerm and LogFilePerm directives.
+ - Increased maximum size of MIME types to IPP_MAX_NAME
+ to allow for longer printer names.
+ - No longer create remote printers when loading job
+ history data.
+ - The printer-make-and-model attribute wasn't set when
+ the PPD file didn't contain a NickName attribute.
+ - Now handle PPD files with translation strings longer
+ than 80 bytes - they are truncated if they go over...
+ - The scheduler didn't handle signals until after it
+ loaded the configuration files the first time; this
+ caused problems on some installations that would
+ restart the scheduler as the system booted into run
+ level 3.
+ - Now throttle broadcasts like we do for polling.
+ - Fixed a bug in the reading of PPD files using CR's
+ instead of CR LF's or LF's.
+ - The scheduler would crash if cupsd.conf contained a
+ BrowseProtocols line with no protocols listed.
+ - The HTML job operation templates now link back to the
+ destination printer or class.
+ - The serial backend now detects USB serial devices.
+ - The LPD mini-daemon (cups-lpd) now passes the
+ job-originating-host-name attribute to the scheduler
+ (cupsd).
+ - Updated the IPP backend to reconnect after downgrading
+ from IPP/1.1 to 1.0, and when sending requests to HP
+ JetDirect interfaces that don't support HTTP
+ Keep-Alive like they should.
+ - Now pass NLSPATH and DYLD_LIBRARY_PATH environment
+ variables, if defined, to CGI and job processes.
+ - Removed the pstoraster filter (based on GNU
+ Ghostscript 5.50) and now provide the raster "driver"
+ and patch file necessary to use the current GNU
+ Ghostscript 7.05 release.
+ - Removed unnecessary fonts and updated the Courier and
+ Symbol fonts to the latest versions to better support
+ non-ISOLatin1 text.
+ - The text filter now always embeds the Courier and
+ Symbol fonts to ensure that they contain the full set
+ of glyphs.
+ - The lp and lpr commands now only override the SIGINT
+ handler if it is not being ignored (patch from Robert
+ Ambrose for some interactive software that catches
+ SIGINT and will gracefully cancel the print...)
+ - The PostScript image filter (imagetops) now supports
+ printing CMYK images using the CMYK colorspace.
+ - The image filters now support CMYK JPEG files, and
+ correctly handles the inverted files from Photoshop
+ (which seems to save RGBW data, not CMYK...)
+ - Added a "check" target to the top-level makefile to
+ conform with GNU standards (same as "test").
+ - The IPP code didn't always map the POSIX locale "C" to
+ the proper IPP language code.
+ - The cupsaddsmb program was updated to use the
+ setdriver command instead of addprinter.
+ - Banner pages were not handled properly for implicit
+ classes.
+ - When tunneling to a remote system using SSH, the
+ printer URIs for local printers on the remote system
+ did not reflect the correct port number.
+ - The Allow, Deny, BrowseAllow, BrowseDeny, and
+ BrowseAddress directives now support the network
+ interface names "@LOCAL" and "@IF(name)" for access
+ control and browsing based on the current interface
+ addresses instead of fixed names or IP addresses.
+ - The texttops filter did not properly recognize the
+ "nowrap" (wrap=false) option.
+ - The InstallableOptions group name in a PPD file is now
+ translated separately (CUPS_MSG_OPTIONS_INSTALLED) so
+ that UIs can accurately detect the presence of this
+ group.
+ - The scheduler no longer keeps job history data for
+ remote printers on the client (just on the server.)
+ - The parallel and USB backends now retry if the backend
+ detects that the printer is not connected to the
+ system (rather than stopping the queue...)
+ - The network backends now retry if the backend detects
+ that the printer is not connected to the network or is
+ unreachable (rather than stopping the queue...)
+ - The cupsGetDests() function no longer lists options
+ and instances for printers that no longer exist.
+ - The scheduler now converts the document language to
+ the correct LANG string.
+ - The cupsaddsmb program now supports alternative CUPS
+ and SAMBA server names.
+ - The PostScript filter now supports the Orientation
+ comment and rotates the page as needed automatically.
+ - Revamped the makefiles slightly to use automatically
+ generated dependencies.
+ - Build fixes for OS X.
+ - The TIFF reading code depended on the newest version
+ of libtiff; now conditionally compile that portion of
+ the loader.
+ - The PPD code now decodes all JCL options in the
+ JCLSetup group, not just those options that start with
+ the prefix "JCL".
+ - The backends now read print data using the read()
+ system call to ensure that the current page is printed
+ while the next page is being processed.
+ - The pdftops filter did not support shading type 3
+ (radial fill) for the "sh" operator.
+ - The cups-polld program now throttles the local
+ broadcasts of polled printers and classes so that the
+ local system is not overwhelmed with hundreds of
+ printers and classes all at once.
+ - Updated the serial backend to support 230,400 baud for
+ the Linux PPC port.
+ - The cupsGetJobs() function wouldn't report completed
+ jobs that did not have a document-format attribute
+ value.
+ - The cupsEncodeOptions() function now maintains a table
+ of known boolean and numeric options, and encodes all
+ other options as strings.
+ - Now add a newline before the end-of-page code in the
+ PostScript filter; this fixes a problem with files
+ that don't end with a newline.
+ - The image filters looked for the "orientation" option
+ instead of the correctly named "orientation-requested"
+ option.
+ - The cupsEncodeOptions() function now handles mixed
+ integers and ranges.
+ - New translation guide for developers to provide native
+ language support for CUPS.
+
+
+CHANGES IN CUPS V1.1.14
+
+ - The ippRead() function did not verify that the
+ attribute name length or string with language value
+ was not larger than the read buffer.
+ - The scheduler set the signal handlers before loading
+ the configuration files the first time; this prevented
+ the RunAsUser directive from blocking server reloads.
+ - Added Swedish message catalog.
+ - The parallel backend now recognizes the /dev/printers
+ device directory under Linux 2.4.x.
+ - MacOS X fixes.
+ - The cupsaddsmb utility sent the server name after the
+ user information when executing the rpcclient program.
+ This caused problems with some versions of SAMBA
+ 2.2.x.
+ - The IPP backend did not pass the requesting user name
+ when checking on the print job status. This prevented
+ it from waiting for the job to complete when
+ communicating with some IPP implementations that
+ require it.
+
+
+CHANGES IN CUPS V1.1.13
+
+ - The lpstat command did not report jobs submitted to
+ regular printer classes.
+ - The texttops filter didn't use sufficient precision
+ when positioning text with some values of cpi and lpi.
+ This could cause the alignment of text to stray.
+ - cupsGetDests() didn't merge the options from the
+ /etc/cups/lpoptions file with ~/.lpoptions - options
+ in ~/.lpoptions overrode them completely.
+ - Added support for KOI8-R and KOI8-U character sets,
+ and added several Russian message catalogs.
+ - The scheduler put the wrong timezone offset in the log
+ files (e.g. +0500 instead of -0500 for EST...)
+ - The scheduler did not ignore trailing whitespace in
+ *.convs files.
+ - The scheduler now forces all processes to exit (kill
+ -9) when it is stopped. This prevents parallel and
+ USB devices from running in the background after cupsd
+ goes away.
+ - The cupsParseOptions() function didn't skip trailing
+ whitespace after quoted values.
+ - More changes to support CUPS on OS/2.
+ - Added Simplified Chinese message catalog.
+ - Added PAM support for IRIX.
+ - The cupsGetPPD() function didn't remove the @server
+ portion of the printer name, and since it would
+ connect immediately to the remote server instead of
+ the local server, the printer would not be found.
+ - Classification and page labels were not rotated to
+ match the page orientation.
+ - Now set the TCP "no delay" option on network
+ connections to improve performance/response time.
+ - Improved the IRIX printing tools support with patches
+ from Andrea Suatoni.
+ - Added a new PrintcapGUI directive to specify the GUI
+ option panel program to use for the IRIX printing
+ tools support.
+ - The cupsGetDests() function did not check to see if a
+ user-defined default printer (set via lpoptions) still
+ existed.
+ - The pstops filter no longer assumes that the default
+ dictionary is writable when doing N-up processing.
+ - The pstops filter now supports printing N-up with the
+ page-set option.
+ - The imagetoraster filter now supports direct printing
+ of CMYK image data without conversion/correction.
+ - The IPP backend now reports printer state/error
+ conditions when possible (toner low, media empty,
+ etc.)
+ - The lpstat command now supports the (undocumented)
+ IRIX -l option ("-lprintername") for a compact job
+ listing for a printer.
+ - The lpstat command now includes printer date/time
+ information in the output (always Jan 01 00:00) to
+ make third-party tools happy.
+ - The text filter now supports non-integer cpi and lpi
+ values.
+ - The Margins field in the CUPS raster header was not
+ initialized by the pstoraster filter.
+ - Added --with-optim="flags" option to configure script.
+ - Updated the Italian message translations.
+ - Updated the cups.list file to install the correct
+ files.
+ - The pstoraster filter accessed the third element of a
+ 2 element array.
+ - The scheduler did not setup a status pipe for polling
+ processes, so error messages went to whatever file
+ descriptor 2 was pointing to when they were started.
+ - The httpMD5Final() function didn't put a colon between
+ the password and nonce strings.
+ - The pstops filter did not default to Binary data for
+ "%%BeginData:".
+ - The pstops filter did not stop processing when a line
+ containing a CTRL-D is seen.
+ - The scheduler no longer replaces the JobSheets values
+ from the printers.conf and classes.conf files with the
+ classification level, if set. This way the original
+ banner settings are preserved when classification
+ levels are changed or turned off.
+ - The serial backend didn't drain the output queue, nor
+ did it restore the original settings.
+ - Updated the default system group under MacOS X.
+ - If no SystemGroup was defined in cupsd.conf, the
+ system default group was not used.
+ - The cups-lpd mini-daemon now supports LPD clients that
+ send multiple control files.
+ - httpConnectEncrypt() now always uses encryption for
+ connections on port 443, since port 443 is reserved
+ for the "https" scheme.
+ - Group authentication via certificates did not work
+ from the web interface for accounts other than
+ "root".
+ - The serial port backend did not clear the OPOST
+ option, which could cause problems with some printers.
+ - The cups-lpd mini-daemon didn't lookup the client IP
+ address properly.
+ - The parallel backend now identifies the polled and
+ interrupt-driven devices under *BSD.
+ - The scheduler allowed the "always" encryption mode
+ inside a Location, which is not valid.
+ - The CUPS startup script now checks for the timezone
+ information under Linux.
+ - Now also map the sides attribute to the JCLDuplex
+ option (if present) in PPD files.
+ - Updated pdftops to Xpdf 0.93a.
+ - Added support for MD5 passwords under Slackware.
+ - Added new AuthType BasicDigest that does Basic
+ authentication using the MD5 password file managed by
+ the lppasswd command.
+ - The banner page attribute substitution code now
+ retains {name} sequences in banner files when the
+ named attribute is undefined. Use {?name} to
+ conditionally substitute an IPP attribute.
+ - The scheduler now ensures that the ServerRoot
+ directory and configuration files are owned by and
+ writable by the User and Group in cupsd.conf.
+ - The USB backend now lists all USB printer devices
+ regardless of whether a printer is connected or not.
+ This allows new USB printers to be connected without
+ restarting cupsd.
+ - Added some more minor performance tweeks to the IPP
+ protocol code to reduce copying and array indexing.
+ - The cupsaddsmb utility now uses the -c option with
+ smbclient and rpcclient to avoid the read length limit
+ for commands on the standard input.
+ - Added an include file to the CRD handling code in
+ pstoraster so that it would compile properly on 64-bit
+ pointer platforms...
+
+
+CHANGES IN CUPS V1.1.12
+
+ - Added "Polish" to the list of known languages for PPD
+ files.
+ - Added missing directory definition to cups-config.
+ - The CUPS-Move-Job operation did not set the
+ destination type for the new destination.
+ - The CUPS-Add-Printer operation did not support the
+ allow=all or deny=none values to clear the per-user
+ printer ACLs.
+ - The SetPrinterAttrs() function did not handle invalid
+ PPD files that were missing the required NickName
+ attribute. It now looks for NickName, ModelName, and
+ then substitutes the string "Bad PPD File" for the
+ printer-make-and-model attribute.
+
+
+CHANGES IN CUPS V1.1.11
+
+ - Added support for embedded TrueType fonts in PDF
+ files.
+ - Added support for PostScript functions in PDF
+ files.
+ - Added new "cupsaddsmb" utility for exporting
+ CUPS printer drivers to SAMBA/Windows clients.
+ - Added preliminary support for Darwin/MacOS X.
+ - The CUPS-Add-Printer operation no longer allows
+ arbitrary scheme names in device URIs to be used - it
+ now restricts the available schemes to those found in
+ the device list (lpinfo -m).
+ - The ippRead() and ipp_read_file() functions could not
+ handle more than IPP_MAX_VALUES (100) values in a
+ 1setOf attribute. These functions have been updated
+ to dynamically allocate more memory as needed, and the
+ IPP_MAX_VALUES constant now represents the allocation
+ increment. [this caused some versions of the
+ GIMP-print drivers to fail since the number of media
+ options exceeded 100...]
+ - The scheduler could crash when BrowseShortNames
+ was set to "No".
+ - The scheduler did not prevent MaxClients from being
+ set to 0, which could cause the scheduler to go in an
+ infinite loop when accepting a request.
+ - Made some performance optimizations in the ippRead()
+ functions to make IPP request/response processing
+ faster.
+ - The accept/reject/enable/disable command did not
+ support properly support the "-h" or default
+ server name.
+ - The scheduler did not save the quota configuration
+ when the job-quota-period attribute was set to 0.
+ - The LPDEST and PRINTER environment variables did not
+ support printer instances.
+ - The text filter now handles more types of boldface and
+ underline formatting.
+ - The cupsTempFd() function did not fail if the
+ temporary directory did not exist; this would cause it
+ to loop indefinitely instead of returning an error
+ (-1).
+ - Stopping (disabling) a printer class did not stop jobs
+ from printing to printers in that class.
+ - The cupsGetDests() function was sending the
+ requested-attributes attribute as a name instead of a
+ keyword; this caused a serious performance problem on
+ slower systems since more information had to be
+ transferred from server to client.
+ - The web interfaces did not always quote < and & in
+ things like the job title. This had the potential for
+ browser-based security violations (on the browser's
+ machine); bug report from SuSE.
+ - The scheduler now treats unauthenticated usernames as
+ case-insensitive when doing quota and allow/deny
+ processing.
+ - The lp command sent the "request ID is ..." message
+ to stderr instead of stdout...
+ - The PostScript filter (pstops) now handles EPS files,
+ adding a showpage command to the files as needed.
+ - The configure script checked for the header
+ file before the JPEG libraries; since the JPEG headers
+ can define HAVE_STDLIB_H, the configure check would
+ cause the JPEG check to fail on some systems.
+ - The scheduler now supports localized banner files,
+ using the subdirectory approach, e.g. the "es"
+ subdirectory under /usr/share/cups/banners is used for
+ the Spanish banner files.
+ - Updated the scheduler so it knows the correct
+ language abbreviation to use for all supported
+ PPD LanguageVersion values. The new code also
+ supports country codes as well, so "English-GB"
+ maps to the "en_GB" locale.
+ - The cups-lpd mini-daemon did not support
+ anonymous printing (no username specified).
+ While the username is REQUIRED by RFC-1179,
+ MacOS clients do not send the REQUIRED username
+ information when printing via LPD.
+ - Added many warning and informational messages
+ to cups-lpd where they were missing.
+ - Added Czech message file contributed by SuSE.
+ - The cups-lpd mini-daemon now returns a non-zero
+ status if an invalid destination or job ID is
+ provided.
+ - The scheduler did not honor the KeepAlive setting in
+ cupsd.conf.
+ - Increased the size of the file read/write buffers to
+ 32k.
+ - *BSD static library creation fixes.
+ - Use mkstemps() instead of tmpnam() in pdftops whenever
+ possible.
+ - Added httpGetHostByName() function as a wrapper around
+ gethostbyname() - some implementations of this
+ function do not support IP addresses (e.g. MacOS X.)
+ - Added casts to all printf's of file lengths, since
+ there is currently no standard way of formatting long
+ long values.
+ - The client filename field was not cleared in all
+ instances, resulting in old form data being submitted
+ to CGIs.
+ - The httpConnect*() functions now try all available
+ addresses for a host when connecting for the first
+ time.
+ - The pstoraster filter would "lose" all drawing
+ commands when the PageSize was set but the printer
+ bitmap was not reallocated. This was most noticeable
+ with the output from StarOffice 6 beta and would
+ result in a blank page being output...
+ - The IPP backend was sending a PAGE comment even when
+ printing the output from a filter (it should only send
+ page comments when printing files directly...)
+ - The pdftops filter didn't properly map glyph names of
+ embedded Asian TrueType fonts.
+ - Changed the CUPS startup script to look for a program
+ named "cupsd", not just any program with "cupsd" in
+ the name (this caused the apcupsd UPS monitoring
+ daemon to be stopped/restarted...)
+ - The CUPS-Move-Job operation did not change the
+ internal destination name for held jobs, so moved (but
+ held) jobs would still show up as queued on the
+ original destination.
+ - The cups-polld program didn't send the
+ requested-attributes attribute in the
+ CUPS-Get-Printers and CUPS-Get-Classes requests, which
+ made it use more CPU and bandwidth than required.
+ - The scheduler and CUPS API incorrectly added a
+ job-sheets-default attribute for remote printers. This
+ caused banner pages to be omitted from client system
+ prints.
+
+
+CHANGES IN CUPS V1.1.10-1
+
+ - Minor fixes to the filter, systemv, and template
+ makefiles to install files properly.
+
+
+CHANGES IN CUPS V1.1.10
+
+ - Added a driver for DYMO label printers.
+ - Added new ClassifyOverride directive to allow users
+ to override the classification of individual jobs.
+ - Added new BrowseProtocols directive to control which
+ browse protocols are used (currently CUPS and SLP).
+ - Added SLPv2 support (thanks to Matt Peterson for
+ contributing the initial implementation for CUPS.)
+ - Adding a raw printer on a remote CUPS server now
+ correctly redirects PPD file requests to the remote
+ server.
+ - The serial backend now limits writes to 1/10th
+ second worth of data to avoid buffer overflows
+ with some types of flow control.
+ - The scheduler did not properly process PUT requests,
+ so configuration files could not be uploaded to the
+ server.
+ - The scheduler did not strip trailing whitespace on
+ lines in the configuration files.
+ - The httpWrite() function did not transition the PUT
+ request to the HTTP_STATUS state to get the status
+ from the server.
+ - The scheduler did not properly handle trailing null
+ ("-") filters when testing a driver that sent data
+ to the file: pseudo-backend.
+ - The IPP backend now only sends a document-format of
+ "application/vnd.cups-raw" when printing to another
+ CUPS server using a local printer driver or interface
+ script. Previously the job's document format was
+ used, which was incorrect.
+ - The lpadmin command didn't use the ppd-name attribute
+ with the -m option; this prevented the use of the
+ "raw" model from the command-line.
+ - The pstoraster filter output draft (1-bit) 6-color
+ output in the wrong order; this resulted in yellow
+ being printed instead of black on Stylus Photo
+ printers.
+ - The pdftops filter did not have the Japanese and
+ Chinese text support compiled into it.
+ - The IPP and AppSocket backends did not clear the
+ "waiting for print job to complete" status message,
+ which caused some confusion... :)
+ - The serial backend now opens the port in "no delay"
+ mode to avoid DCD detection problems with some OS's.
+
+
+CHANGES IN CUPS V1.1.9-1
+
+ - The configure script did not substitute the
+ correct user and group names.
+ - The configure script did not use the full path
+ to the install-sh script when it was used.
+ - The pstoraster filter did not correctly support
+ DuplexTumble mode for printers that used flip
+ duplexing.
+ - The cups.list.in file was missing from the
+ distribution.
+ - The New DeskJet series driver did not use the
+ correct OrderDependency for the Duplex option.
+ - Use read() instead of fread() to read piped
+ print files in lpr/lp. This avoids a bug in the
+ HP-UX 10.20 fread() function.
+ - Updated the pstoraster filter to use the MIPS_FIXADE
+ system call under IRIX to fix bus error problems on
+ R12000 processors (Ghostscript is not 64-bit clean...)
+ - Some Xerox PPD files (most notably the Phaser 790)
+ have illegal whitespace in the option keyword in the
+ OpenUI line. This caused the PageRegion option to not
+ be recognized properly for the Phaser 790.
+
+
+CHANGES IN CUPS V1.1.9
+
+ - Revamped the configure script to use a modular
+ approach for the various tests.
+ - Added --with-openssl-* options to properly reference
+ the OpenSSL libraries in DSOs.
+ - Added --with-cups-user and --with-cups-group
+ options to specify the default user and group for
+ CUPS.
+ - Added AIX shared library support.
+ - Added AIX device discovery for the serial and
+ parallel ports.
+ - Now use install program or script to install
+ directories, files, and symlinks.
+ - Updated pstops filter to use strict handling of EPS
+ files embedded in a PostScript document. The %%EOF
+ handling in 1.1.8 caused some dvips files not to
+ print.
+ - Fixed yet another memory allocation bug in pstoraster
+ that would cause it to crash. This fix also ensures
+ that all memory allocations are done on (at least) a
+ 64-bit boundary.
+ - Fixed Digest authentication - httpGetSubField() didn't
+ skip the Digest keyword.
+ - The scheduler did not properly handle Digest
+ authentication with the new multiple-group support.
+ - The scheduler did not allow usernames that were
+ not in the UNIX password file to be used for Digest
+ authentication from passwd.md5.
+ - The scheduler could not scan PPD files that only used
+ a carriage return (i.e. MacOS PPD files); the new code
+ is also about 40% faster, so servers with thousands of
+ PPD files should start much faster now.
+ - The scheduler now stores the PPD file size and
+ modification times in the ppds.dat file, so it can now
+ incrementally update the PPD database from the model
+ directory, resulting in significantly faster startup
+ times.
+ - The lpinfo command did not return a non-zero status
+ code if an error occurred.
+ - Fixed a bug in the scheduler's UpdateJob() function.
+ Basically, all jobs shared the same status buffer, and
+ the "buffer start" pointer could point to 1 byte
+ before the beginning of the buffer. The new
+ implementation uses a separate buffer for each job and
+ eliminates the buffer start bug.
+ - The IPP backend would send N copies of a document if
+ the receiving device didn't support the copies
+ attribute, even if the upstream driver already added
+ the necessary commands to generate the copies. This
+ was most noticeable with HP printers where N * N
+ copies would come out instead of N.
+ - The PostScript filter (pstops) did not properly handle
+ duplex printing on inkjet printers that provide this
+ option. Copies would be put on the front and back
+ sides of the duplexed page, and the filter did not
+ output an even number of pages.
+ - The backends always caught SIGTERM after they
+ connected to the printer. This prevented raw jobs
+ from being cancelled early.
+ - The cupsSetDests() function now removes any printers,
+ instances, and options that are not defined by the
+ user or server. This should prevent old system-wide
+ options from being used in individual user accounts.
+ - Updated the EPSON printer driver and added PPDs for
+ the newer EPSON Stylus printers that only support the
+ "ESC i" graphics command.
+ - The lpadmin command didn't allow you to add remote
+ printers to a local class.
+ - The lpadmin command didn't allow you to set the
+ options (quotas, etc.) for a class.
+ - The scheduler did not load or save the
+ job-sheets-default attribute for classes.
+ - The scheduler did not automatically recreate remote
+ printers that were part of a class.
+ - It was possible for a printer class to list the same
+ printer more than once.
+ - The scheduler now makes a backup copy of classes.conf
+ and printers.conf before writing the new file.
+ - The lppasswd program incorrectly asked for a new
+ password when deleting an existing MD5 password
+ account.
+ - The scheduler did not match "/printers/name.ppd"
+ against a location of "/printers/name".
+ - The client code did not always handle HTTP encryption
+ upgrades properly.
+ - The client code now caches the last Digest password so
+ it can retry using a new resource path or nonce value,
+ which are included in the MD5 sum sent to the server.
+ This should eliminate unnecessary password prompts
+ when using Digest authentication.
+ - The lppasswd command didn't have a man page.
+ - Updated the PJL detection rules to allow the universal
+ escape to occur anywhere in the first 128 bytes of the
+ file.
+ - The cups-polld program would poll servers continuously
+ with no delay if there was an error contacting the
+ server.
+ - The IPP backend would send an empty job-name or
+ requesting-user-name attribute if the corresponding
+ job attribute was an empty string. While this is
+ allowed by the IPP specification, some HP JetDirect
+ implementations return a client-error-bad-request
+ error if an empty name attribute value is received.
+ The new code only sends these attributes if they are
+ not the empty string.
+ - At least some versions of the HP JetDirect firmware
+ do not correctly implement IPP. Added additional
+ checks to the IPP backend to eliminate extra,
+ unsupported attributes which should normally be
+ ignored by a compliant IPP device.
+ - The scheduler did not copy the complete list of
+ supported file types into the
+ document-format-supported attribute. This caused
+ clients to not send the local file type (such as
+ application/vnd.cups-raw for raw print files) and the
+ corresponding bad output in some cases.
+ - The scheduler did not fully copy attributes from a
+ set-job-attributes request - string attributes were
+ only referenced, which could cause cupsd to crash
+ or behave irratically.
+ - The lp command didn't send the right value for the
+ job-hold-until attribute when "-H resume" was
+ specified.
+ - The IPP backend now returns as soon as a job is
+ completed or reported as "pending-held".
+ - Added new ImplicitAnyClasses and HideImplicitMembers
+ directives to the cupsd.conf file to make implicit
+ classes more usable/transparent to the user.
+ - Clients can now (with the appropriate authentication)
+ retrieve and update the server configuration files
+ using HTTP GET and PUT requests.
+ - The web interface didn't allow you to modify the
+ location or description of the printer.
+ - The pdftops filter now uses its own temporary file
+ function to work with PDF files using LZW compression
+ (which use the uncompress program or gunzip)
+ - The SystemGroup directive now supports specification of
+ multiple groups.
+ - Added new Include directive to cupsd.conf, a la
+ Apache.
+ - Added new pseudo-driver/PPD called "raw" that can be
+ used to create/convert a raw queue. This also allows
+ raw queues to be created in the web interface.
+ - The pdftops filter didn't handle image objects that
+ used JPEG and Flate compression together.
+ - The pstops filter counted pages wrong when using the
+ N-up and even/odd printing options. This prevented
+ the page-ranges option from working properly.
+ - Added another fix to pstoraster for a bus error
+ condition caused by a lack of parenthesis in the
+ Ghostscript code.
+ - Added new "natural-scaling" option which scales the
+ natural size of the image (percent of natural image
+ size instead of percent of page size.)
+ - The lppasswd program is now setuid to the CUPS user
+ instead of root.
+ - The PPD functions did not allow for PPD files that
+ defined the page sizes and margins before the page
+ size options.
+ - The mime.types file now checks for the PJL "LANGUAGE =
+ Postscript" command for PostScript files.
+ - The scheduler did not truncate file: output files.
+ - The PPD file reading code did not handle options with
+ raw quotes (") in the human-readable names.
+ - The pdftops filter now remaps the space character when
+ (bad) PDF files contain a .notdef glyph for the space
+ character.
+
+
+CHANGES IN CUPS V1.1.8
+
+ - Updated spec file to generate separate cups-pstoraster
+ package for pstoraster.
+ - The spec file wasn't setting LOGDIR in the install.
+ - The scheduler might restart a stopped printer after
+ stopping a print job. Thanks to Florent
+ Guiliani for finding this bug!
+ - The init script showed run level 0 for the Red Hat
+ chkconfig program. This is incorrect because Red Hat
+ doesn't use run level 0 for shutdown scripts.
+ - The IPP backend did not handle the
+ client-error-not-found error when checking the status
+ of the job that was sent. This caused remote queues
+ to stop on client machines when the server had job
+ history disabled.
+ - Added httpConnectEncrypt() function to avoid
+ performance penalty for setting up encrypted
+ connections initially.
+ - Use httpConnectEncrypt() in all client apps and in the
+ CUPS API to ensure consistent usage of encryption
+ throughout.
+ - Jobs weren't queued to remote classes (fix from
+ Richard Begg.)
+ - AIX changes from Richard Begg.
+ - Fixed the pstops fix for GNOME output - no longer use
+ the page numbers in the %%Page: comment since GNOME
+ puts a filename instead (!?@!#?!). There is still an
+ issue with N-up printing since GNOME defines its fonts
+ in the first page instead of the document setup section
+ (pages must be independent according to the DSC spec)
+ People with GNOME printing problems should consult bug
+ #54489...
+ - The imagetops filter produced PAGE: messages when
+ generating PostScript for a non-PostScript printer
+ (only affects page-label and Classification
+ options.)
+ - The updated pdftops filter was looking for an options
+ file called xpdf.conf instead of pdftops.conf.
+
+
+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, Require,
+ Satisfy, , , and LimitRequestSize
+ 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.
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 000000000..b2e1670fc
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,286 @@
+CHANGES.txt - 01/12/2006
+------------------------
+
+CHANGES IN CUPS V1.2.0b1
+
+ - The web interface now provides searching, paging, and
+ changing of the sort/display order of classes, jobs,
+ and printers.
+ - cupsaddsmb now accepts a password on the command-line
+ and supports passwords with special characters (STR
+ #822, STR #1236)
+ - ppdLoad*() no longer tries to "fix" bad characters in
+ UI text (STR #1101)
+ - Printer names can now (reliably) contain Unicode
+ characters (STR #896)
+ - The "lpstat -p" command now shows the time and date of
+ the last printer state change instead of the hardcoded
+ "Jan 01 00:00" (STR #659)
+ - The scheduler now adds a job-actual-printer-uri
+ attribute to job objects when printing to a class (STR
+ #116)
+ - The scheduler now logs log file open errors to the
+ system log (STR #1289)
+ - The scheduler now sets the job-originating-user-name to
+ the authenticated username, if available (STR #1318)
+ - The scheduler now only updates the permissions of SSL
+ keys and certificates when they are under the
+ ServerRoot directory (STR #1324)
+ - The rastertodymo driver has been renamed to
+ rastertolabel (a symlink is installed so that existing
+ queues continue to work) and now also supports Zebra's
+ CPCL language.
+ - The lpstat command could show the wrong active job for
+ a printer (STR #1301)
+ - Fixed a potential crash problem in the scheduler when
+ aborting a CGI program (STR #1290)
+ - Added a "cancel all jobs" button to the class and
+ printer web interfaces (STR #1140)
+ - The add-printer web page now shows the
+ set-printer-options page after the printer has been
+ added (STR #690)
+ - The classes web page now provides links to each of the
+ member printers (STR #307)
+ - CUPS now handles HTTP request/response lines up to 32k
+ in length; this is mainly for better cookie support
+ (STR #1274)
+ - Added support for the Apache PassEnv and SetEnv
+ directives to cupsd.conf (STR #853)
+ - Added large file (64-bit) support (STR #541)
+ - Fixed a performance issue with the ippReadIO()
+ implementation (STR #1284)
+ - Fixed a performance issue with the scheduler's implicit
+ class implementation (STR #1283)
+ - The pdftops filter now adds the Title and Creator
+ fields from the PDF file to the PostScript document
+ comments section (STR #539, STR #830)
+ - Added a new cups_array_t and cupsArray*() functions to
+ the CUPS API to support sorted lists of data.
+ - Made the CUPS API library thread-safe (STR #1276)
+ - Added "media" option support for EFI EFMediaType option
+ (STR #902)
+ - Added write buffering to the HTTP code to improve
+ performance (STR #547)
+ - The scheduler now uses the attributes-natural-language
+ attribute to localize banner pages (STR #386)
+ - The scheduler now returns the address that was used to
+ connect to it (STR #1076)
+ - Fixed a problem with N-up printing and OpenOffice (STR
+ #576)
+ - Added support for the GCC position independent
+ executable options (STR #1209)
+ - Added new BrowseLocalProtocols and
+ BrowseRemoteProtocols directives to cupsd.conf,
+ allowing for different browse protocols for local and
+ remote printers (STR #877)
+ - PPD files can now contain strings up to 256k in length
+ (STR #1215)
+ - The pstops filter now supports the IncludeFeature DSC
+ comment (STR #1212)
+ - The pstops filter now disables the setpagedevice
+ procedure when doing N-up printing (STR #1161)
+ - The serial backend now supports "stop=1", "stop=2",
+ "parity=space", and "parity=mark" options (STR #1155)
+ - "make install" no longer overwrites an existing PAM
+ configuration file (STR #1064)
+ - The scheduler now closes all files on startup when run
+ in daemon mode (STR #1009)
+ - Added a new RGBW colorspace to the CUPS raster format
+ (STR #1071)
+ - The pdftops filter now sets the page size based on the
+ media box when not scaling the output (STR #912)
+ - The pdftops filter now supports masked images (STR
+ #281)
+ - The pdftops filter produced large output when rendering
+ PDF files containing lot of repeated images (STR #327)
+ - The pdftops filter now minimizes print processing of
+ PDF files when using the page-ranges option (STR #273)
+ - Updated pdftops filter to Xpdf 3.01.
+ - Added new cupsBackchannelRead() and
+ cupsBackchannelWrite() functions, as well as
+ backchannel support to the parallel, serial, socket,
+ and USB backends (STR #1252)
+ - The parallel and USB backends now treat a "no space
+ available" error as an out-of-paper condition (STR
+ #1225)
+ - The "lpc" command now supports the "status all" command
+ (STR #1004)
+ - ippReadIO() did not read collections properly (STR
+ #1249)
+ - The "make test" script now creates the test files in
+ "/tmp/cups-$USER" instead of "/tmp/$USER" (STR #981)
+ - All backends now abort on error when printing a job to
+ a class - this allows the next printer in the class to
+ print the job (STR #1084)
+ - The scheduler now verifies that a printer supports
+ Letter or A4 media sizes before setting them as the
+ initial default (STR #1250)
+ - The cupstestppd program now flags bad Resolution
+ options (STR #1269)
+ - The USB backend now retries printing when the printer
+ is disconnected or turned off (STR #1267)
+ - Added new httpGetHostname() function to CUPS API, and
+ use it instead of gethostname() so that the web
+ interface will work correctly on systems whose hostname
+ is not the FQDN (STR #1266)
+ - The scheduler now stops printers if the backend for the
+ queue is missing on startup (STR #1265)
+ - The configure script now supports "--disable-library"
+ to disable particular image file format support
+ libraries, even if they are available on the build
+ system (STR #1248)
+ - The IPP backend did not always report on the total
+ number of pages that were printed (STR #1251)
+ - The lpstat program could display garbage date and time
+ values for locales whose date format exceeded 31
+ characters (STR #1263)
+ - The cupstestppd program would segfault when testing
+ certain broken PPD files (STR #1268)
+ - Dramatically reduced the overhead of implicit classes.
+ - Added new cupsDir*() functions to CUPS API.
+ - Printers can now be published individually for sharing.
+ - Fixed a bug in the scheduler's startup signalling code
+ which caused cupsd to send the SIGUSR1 signal to the
+ init process instead of the original parent process
+ (STR #1258)
+ - Added new on-line help CGI to web interface to provide
+ searchable help.
+ - Devices are now tracked dynamically, with each query
+ doing a new device scan. This eliminates a previous
+ startup delay caused by slow backends and allows new
+ printers to be seen without restarting the server,
+ however it limits the amount of device URI checking
+ that can be done (basically now the scheduler only
+ requires a URI with a method that is a listed backend)
+ - Added new printer auto-detection, server configuration,
+ and log file viewing to the administration web page.
+ - Added new "set allowed users" web interface to set the
+ list of allowed users for a printer or class.
+ - The scheduler, command-line, and web interfaces now
+ limit the list of printers and classes to those
+ accessible by a user.
+ - cupsMarkOptions() now handles more non-standard
+ duplexing options and choices (STR #915)
+ - cups-lpd now honors remote banner requests with the
+ "standard" banner whenever a printer does not have one
+ defined (STR #1220)
+ - The scheduler's denial-of-service checks did not work
+ properly with IPv6 addresses (STR #1134)
+ - The lp and lpr commands did not error out properly when
+ they were unable to write to a temporary file (STR
+ #1129)
+ - The pstops filter did not handle Adobe-specific
+ comments in Windows NT driver output (STR #1085)
+ - "lpstat -l -p" incorrectly reported the printer
+ interface (STR #936)
+ - The web interface now operates exclusively with the
+ UTF-8 encoding, and sends the appropriate character set
+ and header information to the web browser (STR #919,
+ STR #1007)
+ - Added a "set allowed users" interface to the web
+ interface so that you can set the list of allowed or
+ denied users/groups for a printer or class.
+ - Disallow the "#" character in printer names, since it
+ has special meaning in the shell, config files, and in
+ URIs (STR #917, STR #1202)
+ - Added a new application/x-csource MIME type, and
+ support for it to the texttops filter so that you can
+ pretty print plain text files without the C/C++
+ keywords being highlighted.
+ - The pdftops filter did not compile with GCC 4.0 (STR
+ #1226)
+ - The texttops filter did not highlight preprocessor
+ directives followed by a tab properly.
+ - HP PJL output now uses both JOB DISPLAY and RDYMSG
+ commands to show the current job on the printer's
+ display (STR #1218)
+ - Local authentication certificates are now stored in
+ /var/run/cups/certs by default instead of
+ /etc/cups/certs (STR #1211)
+ - Backends now use "&" to separate options in device
+ URIs; "+" is still recognized but is deprecated (STR
+ #842)
+ - The USB backend no longer supports the usb:/dev/foo
+ format on systems that support device ID queries.
+ - Forced classification markings did not work when the
+ job-sheets parameters were "none,none".
+ - "lpstat -l -p" incorrectly showed all users as allowed,
+ even if the queue was restricted to certain users (STR
+ #801)
+ - The scheduler now automatically detects SSL/TLS clients
+ without using the SSLPort/SSLListen directives.
+ - The CUPS API and scheduler no longer support SSLv2-
+ encrypted connections.
+ - Updated the cupsaddsmb utility to correctly export the
+ CUPS driver for Windows.
+ - Fixed a signal-handling bug in httpRead() which
+ ultimately caused the server to print multiple copies
+ when it was busy (STR #1184)
+ - The cupsFile API now uses the O_APPEND option when
+ opening files in append mode (STR #990)
+ - The md5.h header and md5_* functions are now officially
+ private and have been renamed to avoid conflicts with
+ other implementations with the same name.
+ - The pdftops filter incorrectly embedded some Type1
+ fonts (STR #1093)
+ - The scheduler didn't detect a closed connection in the
+ middle of an IPP request (STR #1153)
+ - The scheduler could block trying to read the job status
+ if there was input pending and the job was cancelled in
+ the same input cycle (STR #1157)
+ - The scheduler could crash when deleting a class due to
+ infinite recursion.
+ - Updated the Zebra ZPL label printer driver to use the
+ run-length encoding and support more options.
+ - Updated serial backend to scan for /dev/ttyC* as well
+ as /dev/ttyc* for Cyclades serial ports (STR #1049)
+ - The scheduler could hang reading the job status under
+ certain circumstances (STR #1068)
+ - The USB backend termination signal code was inverted
+ (STR #1046)
+ - Moved enable and disable commands to sbindir to be
+ consistent.
+ - Added new cupsRasterInterpretPPD() function for RIP
+ filters to setup the raster page header from
+ PostScript commands in a PPD file.
+ - The CUPS browsing protocol now offers a "delete" bit
+ to remove printers as soon as they are deleted on the
+ server or as soon as the server shuts down gracefully
+ (STR #793)
+ - The CUPS_SERVER and ServerName directives (client.conf
+ and ~/.cupsrc) may now contain names of the form
+ "server:port" and "/path/to/domain/socket".
+ - The "cancel -u user" command now works for ordinary
+ users (STR #751)
+ - Added test run support to "make test" target (STR #64)
+ - Added domain socket support (STR #656)
+ - Added BrowseLocalOptions directive to allow the
+ administrator to add printer URI options to the browse
+ URI, e.g. "encryption=required" (STR #732)
+ - Added BrowseRemoteOptions directive to allow the
+ administrator to add standard URI options to the
+ remote printer URI, e.g. "encryption=required" (STR
+ #732)
+ - Now put "-I.." compiler option in front of all others
+ to ensure that local CUPS headers are used before
+ installed headers (STR #437)
+ - New cupsLangPrintf() and cupsLangPuts() for localized
+ interfaces.
+ - Now support custom attributes and extended options in
+ PPD files.
+ - Now provide functions to save PPD files.
+ - New policy mechanism allows per-operation and
+ per-printer control over what users and groups are
+ allowed to do various IPP operations.
+ - New error policy mechanism to control how aborted
+ backend errors are handled by the scheduler
+ (abort-job, retry-job, requeue-job, stop-printer)
+ - Updated the printer test page with a better color
+ wheel and a separate grayscale ramp.
+ - A single backend process is now run to send all print
+ data for a job.
+ - Backends and filters can now send and receive
+ backchannel data over file descriptor 3.
+ - Updated the raster stream format to support more
+ user-defined attributes and to do compression of the
+ page data.
diff --git a/CREDITS.txt b/CREDITS.txt
new file mode 100644
index 000000000..522774972
--- /dev/null
+++ b/CREDITS.txt
@@ -0,0 +1,33 @@
+CREDITS.txt - 04/26/2003
+------------------------
+
+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.
+ L. Peter Deutsch - MD5 code.
+ Dr. ZP Han - setgid()/setuid().
+ Guy Harris - *BSD shared libraries and lots of other fixes.
+ Bjoern Jacke - I18N stuff.
+ Wang Jian - CUPS RPM corrections.
+ Roderick Johnstone - Beta tester of the millenium.
+ Till Kamppeter - Bug fixes, beta testing, evangelism.
+ Kiko - Bug fixes.
+ Sergey V. Kovalyov - ESP Print Pro and CUPS beta tester.
+ Mark Lawrence - Microsoft interoperability testing.
+ Jeff Licquia - Bug fixes, beta testing, evangelism.
+ Jason McMullan - Original CUPS RPM distributions.
+ Wes Morgan - *BSD fixes.
+ Ulrich Oldendorf - German locale.
+ Giulio Orsero - Bug fixes and testing.
+ Kurt Pfeifle - Bug fixes, beta testing, evangelism.
+ Gilles QUERRET - French man pages.
+ Petter Reinholdtsen - HP-UX compiler stuff.
+ Stuart Stevens - HP JetDirect IPP information.
+ Andrea Suatoni - IRIX desktop integration and testing.
+
+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 000000000..e0e3ba9ff
--- /dev/null
+++ b/ENCRYPTION.txt
@@ -0,0 +1,142 @@
+ENCRYPTION - CUPS v1.1.20 - 11/24/2003
+--------------------------------------
+
+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, GNU
+TLS, or CDSA libraries which do.
+
+
+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, GNU TLS, or CDSA libraries 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, GNU TLS, or CDSA libraries from:
+
+ http://www.openssl.org/
+ http://www.gnutls.org/
+ http://www.intel.com/labs/archive/cdsa.htm
+
+
+CONFIGURING WITH ENCRYPTION SUPPORT
+
+Once you have the OpenSSL, GNU TLS, or CDSA libraries installed,
+you'll need to configure CUPS to use it with the "--enable-ssl"
+option:
+
+ ./configure --enable-ssl
+
+If the library 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 000000000..fd2e5ec57
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,190 @@
+INSTALL - CUPS v1.2.0a1 - 01/07/2003
+------------------------------------
+
+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".
+
+**** IF YOU HAVE A NON-POSTSCRIPT PRINTER, YOU WILL ALSO ****
+**** NEED TO INSTALL ESP GHOSTSCRIPT OR A PATCHED VERSION ****
+**** OF THE STANDARD GHOSTSCRIPT RELEASES. ****
+
+
+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.
+
+Also, please note that CUPS no longer includes the Ghostscript-
+based pstoraster filter. You *must* download Ghostscript
+separately and patch it using the files in the pstoraster
+subdirectory, or download the ESP Ghostscript distribution from
+the CUPS web site. For more information see the README file in
+the pstoraster subdirectory.
+
+
+COMPILING FROM CVS
+
+The CUPS CVS repository doesn't hold a copy of the pre-built
+configure script. You'll need to run the GNU autoconf software
+(2.52 or higher) before compiling the software from CVS:
+
+ autoconf ENTER
+
+
+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, DSOFLAGS,
+and LDFLAGS environment variables prior to running configure:
+
+ setenv CFLAGS "-I/some/directory" ENTER
+ setenv CXXFLAGS "-I/some/directory" ENTER
+ setenv DSOFLAGS "-L/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
+ DSOFLAGS="-L/some/directory"; export DSOFLAGS 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
+
+If the OpenSSL header files and libraries are not in a standard
+location, specify the locations of these files using the
+--with-openssl-includes and --with-openssl-libs directives:
+
+ ./configure --enable-ssl \
+ --with-openssl-includes=/foo/bar/include \
+ --with-openssl-libs=/foo/bar/lib
+
+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, NetBSD, or OpenBSD type:
+
+ 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, NetBSD, or OpenBSD:
+
+ 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 EPM 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, NetBSD, and OpenBSD. The target 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.
+ aix - Builds an AIX binary distribution.
+ bsd - Builds a *BSD binary distribution.
+ deb - Builds a Debian binary distribution.
+ depot - Builds a HP-UX binary distribution.
+ pkg - Builds a Solaris binary distribution.
+ rpm - Builds a RPM 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 000000000..2008a6312
--- /dev/null
+++ b/LICENSE.html
@@ -0,0 +1,1068 @@
+
+
+ Software License Agreement - Common UNIX Printing System
+
+
+
+
+Common UNIX Printing System License Agreement
+
+Copyright 1997-2006 by Easy Software Products
+44141 AIRPORT VIEW DR STE 204
+HOLLYWOOD, MARYLAND 20636 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, with exceptions for Apple operating systems and the
+OpenSSL toolkit. A copy of the exceptions and 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
+"cups" include directory and library files in the binary
+distributions. The GNU GPL applies to the remainder of the CUPS
+distribution, including the "pdftops" filter which is based upon
+Xpdf and the CUPS imaging library.
+
+
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
+only exceptions to this are the portions of the CUPS software
+covered by the Apple operating system license exceptions
+outlined later in this license agreement.
+
+
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.
+
+
License Exceptions
+
+In addition, as the copyright holder of CUPS, Easy Software
+Products grants the following special exceptions:
+
+
+
+ - Apple Operating System Development License
+ Exception;
+
+
+
+ - Software that is developed by any person or
+ entity for an Apple Operating System ("Apple
+ OS-Developed Software"), including but not
+ limited to Apple and third party printer
+ drivers, filters, and backends for an Apple
+ Operating System, that is linked to the CUPS
+ imaging library or based on any sample filters
+ or backends provided with CUPS shall not be
+ considered to be a derivative work or collective
+ work based on the CUPS program and is exempt
+ from the mandatory source code release clauses
+ of the GNU GPL. You may therefore distribute
+ linked combinations of the CUPS imaging library
+ with Apple OS-Developed Software without
+ releasing the source code of the Apple
+ OS-Developed Software. You may also use sample
+ filters and backends provided with CUPS to
+ develop Apple OS-Developed Software without
+ releasing the source code of the Apple
+ OS-Developed Software.
+
+ - An Apple Operating System means any
+ operating system software developed and/or
+ marketed by Apple Computer, Inc., including but
+ not limited to all existing releases and
+ versions of Apple's Darwin, Mac OS X, and Mac OS
+ X Server products and all follow-on releases and
+ future versions thereof.
+
+ - This exception is only available for Apple
+ OS-Developed Software and does not apply to
+ software that is distributed for use on other
+ operating systems.
+
+ - All CUPS software that falls under this
+ license exception have the following text at the
+ top of each source file:
+
+
This file is subject to the Apple
+ OS-Developed Software
+ exception.
+
+
+
+ - OpenSSL Toolkit License Exception;
+
+
+
+ - Easy Software Products explicitly allows the
+ compilation and distribution of the CUPS
+ software with the OpenSSL Toolkit.
+
+
+
+
+
+No developer is required to provide these exceptions in a
+derived work.
+
+
Trademarks
+
+Easy Software Products has trademarked the Common UNIX
+Printing System, CUPS, and CUPS logo. You may use these names
+and logos in any direct port or binary distribution of CUPS.
+Please contact Easy Software Products for written permission to
+use them in derivative products. 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 "pdftops" filter
+that is based on the Xpdf 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:
+
+
+http://www.easysw.com/
+
+
+
+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
+
+
+
+- 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.
+
+
- 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.
+
+
- 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:
+
+
+
+- You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+
- 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.
+
+
- 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.
+
+
- 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:
+
+
+
+- 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,
+
+
- 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,
+
+
- 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.
+
+
- 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.
+
+
- 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.
+
+
- 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.
+
+
- 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.
+
+
- 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.
+
+
- 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.
+
+
- 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
+
+
+
+- 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.
+
+
- 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
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+
To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy name of author
+
+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.
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+
If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+
+Gnomovision version 69, Copyright (C) year name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+
+
+The hypothetical commands `show w' and `show c' should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and
+`show c'; they could even be mouse-clicks or menu items--whatever
+suits your program.
+
+
You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+
+
+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:
+
+
+
+ - The modified work must itself be a software library.
+
+
+
- You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+
+
- You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+
+
- 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:
+
+
+
+ - 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.)
+
+
+
- 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.
+
+
+
- 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.
+
+
+
- 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:
+
+
+
+ - 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.
+
+
+
- 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
+
+How to Apply These Terms to Your New Libraries
+
+If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+
To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+one line to give the library's name and an idea of what it does.
+Copyright (C) year name of author
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+
You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the library `Frob' (a library for tweaking knobs) written
+by James Random Hacker.
+
+signature of Ty Coon, 1 April 1990
+Ty Coon, President of Vice
+
+
+That's all there is to it!
+
+
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 000000000..12e4af6bc
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,964 @@
+ Common UNIX Printing System License Agreement
+
+ Copyright 1997-2006 by Easy Software Products
+ 44141 AIRPORT VIEW DR STE 204
+ HOLLYWOOD, MARYLAND 20636 USA
+
+ Voice: +1.301.373.9600
+ Email: cups-info@cups.org
+ WWW: http://www.cups.org
+
+
+INTRODUCTION
+
+The Common UNIX Printing System(tm), ("CUPS(tm)"), is provided
+under the GNU General Public License ("GPL") and GNU Library
+General Public License ("LGPL"), Version 2, with exceptions for
+Apple operating systems and the OpenSSL toolkit. A copy of the
+exceptions and 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
+"cups" include directory and library files in the binary
+distributions. The GNU GPL applies to the remainder of the CUPS
+distribution, including the "pdftops" filter which is based upon
+Xpdf and the CUPS imaging library.
+
+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 only
+exceptions to this are the portions of the CUPS software covered
+by the Apple operating system license exceptions outlined later
+in this license agreement.
+
+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.
+
+
+LICENSE EXCEPTIONS
+
+In addition, as the copyright holder of CUPS, Easy Software
+Products grants the following special exceptions:
+
+ 1. Apple Operating System Development License Exception;
+
+ a. Software that is developed by any person or entity
+ for an Apple Operating System ("Apple OS-Developed
+ Software"), including but not limited to Apple and
+ third party printer drivers, filters, and backends
+ for an Apple Operating System, that is linked to the
+ CUPS imaging library or based on any sample filters
+ or backends provided with CUPS shall not be
+ considered to be a derivative work or collective work
+ based on the CUPS program and is exempt from the
+ mandatory source code release clauses of the GNU GPL.
+ You may therefore distribute linked combinations of
+ the CUPS imaging library with Apple OS-Developed
+ Software without releasing the source code of the
+ Apple OS-Developed Software. You may also use sample
+ filters and backends provided with CUPS to develop
+ Apple OS-Developed Software without releasing the
+ source code of the Apple OS-Developed Software.
+
+ b. An Apple Operating System means any operating system
+ software developed and/or marketed by Apple Computer,
+ Inc., including but not limited to all existing
+ releases and versions of Apple's Darwin, Mac OS X,
+ and Mac OS X Server products and all follow-on
+ releases and future versions thereof.
+
+ c. This exception is only available for Apple
+ OS-Developed Software and does not apply to software
+ that is distributed for use on other operating
+ systems.
+
+ d. All CUPS software that falls under this license
+ exception have the following text at the top of each
+ source file:
+
+ This file is subject to the Apple OS-Developed
+ Software exception.
+
+ 2. OpenSSL Toolkit License Exception;
+
+ a. Easy Software Products explicitly allows the
+ compilation and distribution of the CUPS software
+ with the OpenSSL Toolkit.
+
+No developer is required to provide these exceptions in a
+derived work.
+
+
+TRADEMARKS
+
+Easy Software Products has trademarked the Common UNIX Printing
+System, CUPS, and CUPS logo. You may use these names and logos
+in any direct port or binary distribution of CUPS. Please
+contact Easy Software Products for written permission to use
+them in derivative products. 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 "pdftops" filter that
+is based on the Xpdf 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:
+
+ http://www.easysw.com/
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 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
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. 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
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C) 19yy
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+ 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.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ 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:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) 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:
+
+ a) 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.)
+
+ b) 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.
+
+ c) 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.
+
+ d) 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:
+
+ a) 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.
+
+ b) 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
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Makedefs.in b/Makedefs.in
new file mode 100644
index 000000000..7829d96b4
--- /dev/null
+++ b/Makedefs.in
@@ -0,0 +1,193 @@
+#
+# "$Id: Makedefs.in 4836 2005-11-13 06:14:46Z mike $"
+#
+# Common makefile definitions for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+#
+# Programs...
+#
+
+AR = @AR@
+AWK = @AWK@
+CC = @LIBTOOL@ @CC@
+CXX = @LIBTOOL@ @CXX@
+DSO = @DSO@
+HTMLDOC = @HTMLDOC@
+INSTALL = @INSTALL@
+LIBTOOL = @LIBTOOL@
+LN = @LN@ -sf
+MV = @MV@
+RANLIB = @RANLIB@
+RM = @RM@ -f
+SED = @SED@
+SHELL = /bin/sh
+STRIP = @STRIP@
+
+#
+# Installation programs...
+#
+
+INSTALL_BIN = $(LIBTOOL) $(INSTALL) -m 755 -s
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_DIR = $(INSTALL) -d
+INSTALL_LIB = $(LIBTOOL) $(INSTALL) -m 755
+INSTALL_MAN = $(INSTALL) -m 644
+INSTALL_SCRIPT = $(INSTALL) -m 755
+
+#
+# Default user and group for the scheduler...
+#
+
+CUPS_USER = @CUPS_USER@
+CUPS_GROUP = @CUPS_GROUP@
+
+#
+# Libraries...
+#
+
+LIBCUPS = @LIBCUPS@
+LIBCUPSIMAGE = @LIBCUPSIMAGE@
+LIBJPEG = @LIBJPEG@
+LIBMALLOC = @LIBMALLOC@
+LIBPAPER = @LIBPAPER@
+LIBPNG = @LIBPNG@
+LIBSLP = @LIBSLP@
+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 = @ARFLAGS@
+BACKLIBS = @BACKLIBS@
+CFLAGS = -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CFLAGS@ \
+ @LARGEFILE@ $(OPTIONS)
+COMMONLIBS = @LIBS@
+CXXFLAGS = -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CXXFLAGS@ \
+ @LARGEFILE@ $(OPTIONS)
+CXXLIBS = @CXXLIBS@
+DSOFLAGS = @DSOFLAGS@
+DSOLIBS = @DSOLIBS@ $(COMMONLIBS)
+IMGLIBS = @IMGLIBS@ -lm
+LDFLAGS = -L../cups -L../filter $(RC_CFLAGS) @LDFLAGS@ $(OPTIM)
+LINKCUPS = @LINKCUPS@ $(SSLLIBS)
+LINKCUPSIMAGE = @LINKCUPSIMAGE@
+LIBS = $(LINKCUPS) $(COMMONLIBS)
+OPTIM = @OPTIM@
+OPTIONS =
+PAMLIBS = @PAMLIBS@
+SSLFLAGS = @SSLFLAGS@
+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@
+
+BUILDROOT = $(DSTROOT)
+
+AMANDIR = $(BUILDROOT)@AMANDIR@
+BINDIR = $(BUILDROOT)@bindir@
+CACHEDIR = $(BUILDROOT)@CUPS_CACHEDIR@
+DATADIR = $(BUILDROOT)@CUPS_DATADIR@
+DOCDIR = $(BUILDROOT)@CUPS_DOCROOT@
+INCLUDEDIR = $(BUILDROOT)$(includedir)
+INITDIR = @INITDIR@
+INITDDIR = @INITDDIR@
+LIBDIR = $(BUILDROOT)$(libdir)
+LOCALEDIR = $(BUILDROOT)@CUPS_LOCALEDIR@
+LOGDIR = $(BUILDROOT)@CUPS_LOGDIR@
+MANDIR = $(BUILDROOT)@mandir@
+PMANDIR = $(BUILDROOT)@PMANDIR@
+REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@
+SBINDIR = $(BUILDROOT)@sbindir@
+SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@
+SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@
+STATEDIR = $(BUILDROOT)@CUPS_STATEDIR@
+
+MAN1EXT = @MAN1EXT@
+MAN5EXT = @MAN5EXT@
+MAN8EXT = @MAN8EXT@
+MAN8DIR = @MAN8DIR@
+
+PAMDIR = $(BUILDROOT)@PAMDIR@
+PAMFILE = @PAMFILE@
+
+
+#
+# Rules...
+#
+
+.SILENT:
+.SUFFIXES: .1 .1.gz .1m .1m.gz .5 .5.gz .8 .8.gz .a .c .cxx .h .man .o .gz
+
+.c.o:
+ echo Compiling $<...
+ $(CC) $(OPTIM) $(CFLAGS) -c $<
+
+.cxx.o:
+ echo Compiling $<...
+ $(CXX) $(OPTIM) $(CXXFLAGS) -c $<
+
+.man.1 .man.1m .man.5 .man.8:
+ echo Linking $<...
+ $(RM) $@
+ $(LN) $< $@
+
+.man.1.gz .man.1m.gz .man.5.gz .man.8.gz .man.gz:
+ echo -n Compressing $<...
+ $(RM) $@
+ gzip -v9 <$< >$@
+
+
+#
+# End of "$Id: Makedefs.in 4836 2005-11-13 06:14:46Z mike $"
+#
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..5d28e1bfa
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,171 @@
+#
+# "$Id: Makefile 4835 2005-11-12 22:00:16Z mike $"
+#
+# Top-level Makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2004 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-3142 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+include Makedefs
+
+#
+# Directories to make...
+#
+
+DIRS = cups backend berkeley cgi-bin filter man pdftops \
+ notifier scheduler systemv
+
+#
+# Make all targets...
+#
+
+all:
+ chmod +x cups-config
+ 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
+
+#
+# Make dependencies
+#
+
+depend:
+ for dir in $(DIRS); do\
+ echo Making dependencies in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) depend) || exit 1;\
+ done
+
+
+#
+# Install object and target files...
+#
+
+install: installhdrs
+ 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 cups-config script...
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_SCRIPT) cups-config $(BINDIR)/cups-config
+ echo Installing startup script...
+ if test "x$(INITDIR)" != "x"; then \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/init.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/init.d/cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc0.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc0.d/K00cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc2.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc2.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc3.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc3.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc5.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc5.d/S99cups; \
+ fi
+ if test "x$(INITDIR)" = "x" -a "x$(INITDDIR)" != "x"; then \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR); \
+ if test "$(INITDDIR)" = "/System/Library/StartupItems/PrintingServices"; then \
+ $(INSTALL_SCRIPT) cups.osx $(BUILDROOT)$(INITDDIR)/PrintingServices; \
+ $(INSTALL_DATA) cups.plist $(BUILDROOT)$(INITDDIR)/StartupParameters.plist; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR)/Resources/English.lproj; \
+ $(INSTALL_DATA) cups.strings $(BUILDROOT)$(INITDDIR)/Resources/English.lproj/Localizable.strings; \
+ else \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
+ fi \
+ fi
+
+
+#
+# Install source and header files...
+#
+
+installsrc:
+ gnutar --dereference --exclude=CVS -cf - . | gnutar -C $(SRCROOT) -xf -
+
+installhdrs:
+ (cd cups ; $(MAKE) $(MFLAGS) installhdrs) || exit 1;\
+ (cd filter ; $(MAKE) $(MFLAGS) installhdrs) || exit 1;
+
+
+#
+# Run the test suite...
+#
+
+check 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
+
+aix:
+ epm $(EPMFLAGS) -f aix cups packaging/cups.list
+
+bsd:
+ epm $(EPMFLAGS) -f bsd cups packaging/cups.list
+
+epm:
+ epm $(EPMFLAGS) cups packaging/cups.list
+
+rpm:
+ epm $(EPMFLAGS) -f rpm cups packaging/cups.list
+
+deb:
+ epm $(EPMFLAGS) -f deb cups packaging/cups.list
+
+depot:
+ epm $(EPMFLAGS) -f depot cups packaging/cups.list
+
+pkg:
+ epm $(EPMFLAGS) -f pkg cups packaging/cups.list
+
+tardist:
+ epm $(EPMFLAGS) -f tardist cups packaging/cups.list
+
+#
+# End of "$Id: Makefile 4835 2005-11-12 22:00:16Z mike $".
+#
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000..c2f964832
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,290 @@
+README - CUPS v1.2.0b1 - 01/10/2006
+-----------------------------------
+
+*****************************************************************
+*****************************************************************
+**** ****
+**** WARNING: THIS IS BETA RELEASE SOFTWARE AND MAY BE ****
+**** TOTALLY UNSTABLE. DO NOT USE IN ENVIRONMENTS ****
+**** WHERE RELIABLE SOFTWARE IS REQUIRED! ****
+**** ****
+*****************************************************************
+*****************************************************************
+
+Looking for compile instructions? Read the file "INSTALL.txt"
+instead...
+
+*****************************************************************
+*****************************************************************
+**** ****
+**** IF YOU HAVE A NON-POSTSCRIPT PRINTER, YOU WILL ALSO ****
+**** NEED TO INSTALL ESP GHOSTSCRIPT OR A PATCHED VERSION ****
+**** OF A STANDARD GHOSTSCRIPT RELEASE. ****
+**** ****
+*****************************************************************
+*****************************************************************
+
+
+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 includes an image file RIP that supports printing of image
+files to non-PostScript printers. A customized version of GNU
+Ghostscript for CUPS called ESP Ghostscript is available
+separately to support printing of PostScript files within the
+CUPS driver framework. Sample drivers for Dymo, EPSON, HP, and
+OKIDATA printers are included that use these filters.
+
+Drivers for thousands of 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:
+
+ - AIX 4.3 or higher
+ - HP-UX 11.00 or higher
+ - IRIX 6.5 or higher
+ - Linux 2.4 with glibc 2.2 or higher
+ - Solaris 7 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! We also
+provide many discussion forums which are available at:
+
+ http://www.cups.org/newsgroups.php
+
+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.2 includes a 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:
+
+ 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
+ ----------------------------- ------------
+ Dymo Label Printers dymo.ppd
+ EPSON Stylus Color Series stcolor.ppd
+ EPSON Stylus Photo Series stphoto.ppd
+ EPSON Stylus New Color Series stcolor2.ppd
+ EPSON Stylus New Photo Series stphoto2.ppd
+ EPSON 9-pin Series epson9.ppd
+ EPSON 24-pin Series epson24.ppd
+ HP DeskJet Series deskjet.ppd
+ HP New DeskJet Series deskjet2.ppd
+ HP LaserJet Series laserjet.ppd
+ OKIDATA 9-Pin Series okidata9.ppd
+ OKIDATA 24-Pin Series okidat24.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-2006 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 PDF filter (pdftops) is based on the Xpdf software,
+Copyright 1996-2005 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 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
+Derek B. Noonburg who developed the Xpdf software used to print
+PDF files.
diff --git a/backend/Dependencies b/backend/Dependencies
new file mode 100644
index 000000000..70897ad97
--- /dev/null
+++ b/backend/Dependencies
@@ -0,0 +1,25 @@
+# DO NOT DELETE
+
+betest.o: ../cups/string.h ../config.h
+ipp.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h
+ipp.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h
+ipp.o: ../cups/file.h ../cups/language.h ../cups/array.h ../cups/string.h
+lpd.o: ../cups/backend.h ../cups/http-private.h ../config.h ../cups/http.h
+lpd.o: ../cups/md5.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h
+lpd.o: ../cups/file.h ../cups/string.h
+parallel.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+parallel.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h
+parallel.o: ../config.h ieee1284.c ../cups/debug.h
+scsi.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+scsi.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h
+scsi.o: ../config.h
+serial.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+serial.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h
+serial.o: ../config.h
+socket.o: ../cups/backend.h ../cups/http-private.h ../config.h ../cups/http.h
+socket.o: ../cups/md5.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h
+socket.o: ../cups/file.h ../cups/string.h
+test1284.o: ../cups/string.h ../config.h ieee1284.c ../cups/debug.h
+usb.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+usb.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h
+usb.o: ../config.h
diff --git a/backend/Makefile b/backend/Makefile
new file mode 100644
index 000000000..26ce19b4f
--- /dev/null
+++ b/backend/Makefile
@@ -0,0 +1,178 @@
+#
+# "$Id: Makefile 4903 2006-01-10 20:02:46Z mike $"
+#
+# Backend makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2006 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+BACKENDS = ipp lpd parallel scsi serial socket usb
+TARGETS = betest test1284 $(BACKENDS)
+OBJS = betest.o ipp.o lpd.o parallel.o scsi.o \
+ serial.o socket.o test1284.o usb.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) http
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all
+ $(INSTALL_DIR) $(SERVERBIN)/backend
+ for file in $(BACKENDS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/backend; \
+ done
+ $(RM) $(SERVERBIN)/backend/http
+ $(LN) ipp $(SERVERBIN)/backend/http
+
+
+#
+# betest
+#
+
+betest: betest.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o betest betest.o $(LIBS)
+
+
+#
+# test1284
+#
+
+test1284: test1284.o ../cups/libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a
+
+
+#
+# ieee1394
+#
+
+ieee1394: ieee1394.o ieee1394-linux.o
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o ieee1394 ieee1394.o ieee1394-linux.o -lraw1394 $(LIBS)
+
+ieee1394.o: ieee1394.h
+ieee1394-linux.o: ieee1394.h
+
+
+#
+# ipp
+#
+
+ipp: ipp.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS)
+ $(RM) http
+ $(LN) ipp http
+
+
+#
+# lpd
+#
+
+lpd: lpd.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpd lpd.o $(LIBS)
+
+
+#
+# parallel
+#
+
+parallel: parallel.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o parallel parallel.o $(LIBS)
+
+
+#
+# scsi
+#
+
+scsi: scsi.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o scsi scsi.o $(LIBS)
+
+scsi.o: scsi.c scsi-irix.c scsi-linux.c
+
+
+#
+# serial
+#
+
+serial: serial.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o serial serial.o $(BACKLIBS) $(LIBS)
+
+
+#
+# socket
+#
+
+socket: socket.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o socket socket.o $(LIBS)
+
+
+#
+# usb
+#
+
+usb: usb.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o usb usb.o $(BACKLIBS) $(LIBS)
+usb.o: usb.c usb-darwin.c usb-unix.c ieee1284.c
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id: Makefile 4903 2006-01-10 20:02:46Z mike $".
+#
diff --git a/backend/betest.c b/backend/betest.c
new file mode 100644
index 000000000..f0ea6cdb2
--- /dev/null
+++ b/backend/betest.c
@@ -0,0 +1,87 @@
+/*
+ * "$Id: betest.c 4494 2005-02-18 02:18:11Z mike $"
+ *
+ * Backend test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * 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: betest.c 4494 2005-02-18 02:18:11Z mike $".
+ */
diff --git a/backend/easysw-firewire-design.txt b/backend/easysw-firewire-design.txt
new file mode 100644
index 000000000..194c487ed
--- /dev/null
+++ b/backend/easysw-firewire-design.txt
@@ -0,0 +1,71 @@
+Preliminary Design for CUPS Firewire Printer Backend - 03/19/2002
+-----------------------------------------------------------------
+
+OVERVIEW
+
+ Easy Software Products will develop an IEEE-1394, a.k.a.
+ Firewire, printing interface for its Common UNIX Printing
+ System ("CUPS") for initial use under the Linux operating
+ system. A follow-on implementation for MacOS X is
+ anticipated as well.
+
+ The operating system interfaces for IEEE-1394 ports vary
+ widely; the CUPS printing interface will abstract the OS
+ layer to a simpler interface geared towards discovering,
+ opening, reading from, writing to, and closing IEEE-1394
+ printers.
+
+ The initial development of the CUPS backend will be targeted
+ at the EPSON Stylus Pro 10000 large format printer, which
+ requires the bandwidth provided by Firewire in order to
+ print at full speed. This printer supports printing via
+ Serial Bus Protocol 2 (SBP-2) using the SCSI and PWG command
+ sets. The CUPS backend will implement the PWG command set on
+ LUN 0 only.
+
+
+OS ABSTRACTION LAYER
+
+ The OS abstraction layer will be a thin client library that
+ implements the following functions:
+
+ ieee1394_list
+ ieee1394_open
+ ieee1394_close
+ ieee1394_read
+ ieee1394_write
+ ieee1394_error
+
+ The "ieee1394_list" function will list all of the available
+ printer devices on the bus. The device information will
+ consist of the device URI (ieee1394:/something) used to
+ access the device and the make and model information, if
+ available, for the device ("EPSON Stylus Printer").
+
+ The "ieee1394_open" and "ieee1394_close" functions will open
+ and close a connection to the printer, respectively.
+
+ The "ieee1394_read" and "ieee1394_write" functions will read
+ and write data to and from the printer, respectively. The
+ read function will be non-blocking, returning data only if
+ there is data coming back from the printer.
+
+ The "ieee1394_error" function will return a string
+ describing the last error or NULL if no error occurred.
+
+ The library will be responsible for creating any background
+ threads that are needed to monitor the connection to the
+ printer.
+
+
+CUPS BACKEND
+
+ The CUPS backend will use the OS abstraction layer to list
+ and access the Firewire printers. The "main" function will
+ read and write printer data, while the "list_devices"
+ function will be called as necessary to identify the
+ available devices.
+
+ The CUPS 1.1 backend will record any status information in
+ the error log file, while the 1.2 backend will supply it to
+ the printer driver process.
diff --git a/backend/easysw-firewire-linux.txt b/backend/easysw-firewire-linux.txt
new file mode 100644
index 000000000..a8e461189
--- /dev/null
+++ b/backend/easysw-firewire-linux.txt
@@ -0,0 +1,35 @@
+Easy Software Products
+44141 Airport View Drive
+Suite 204
+Hollywood, Maryland 20636
++1.301.373.9600
+March 8, 2002
+
+
+Subject: EPSON Firewire Printer Driver for Linux
+
+Currently, no Firewire printer support exists for Linux. Since
+the latest EPSON printer products depend on the Firewire
+interface to print at full speed, a solution is needed to
+support customers using Linux as their server platform.
+
+The Linux Firewire subsystem provides a user-mode driver
+interface that allows driver programs to access Firewire
+devices. Easy Software Products will utilize this interface to
+develop a "backend" program for the Common UNIX Printing System
+that will allow users to print to EPSON printers using the
+Firewire interface.
+
+After examining the Linux interface, we estimate that it will
+require approximately 30 hours of development time to write,
+test, and document the Firewire backend, for a total cost of
+$3,000. The new backend will become a standard part of the CUPS
+software distribution and will be included with at least the
+following Linux distributions:
+
+ - Caldera Linux
+ - Mandrake Linux
+ - Red Hat Linux
+ - SuSE Linux
+
+ESP will provide EPSON with binaries for Red Hat Linux 7.2.
diff --git a/backend/ieee1284.c b/backend/ieee1284.c
new file mode 100644
index 000000000..6152c4c7a
--- /dev/null
+++ b/backend/ieee1284.c
@@ -0,0 +1,373 @@
+/*
+ * "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $"
+ *
+ * IEEE-1284 support functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * get_device_id() - Get the IEEE-1284 device ID string and corresponding
+ * URI.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#ifdef __linux
+# include
+# include
+# define IOCNR_GET_DEVICE_ID 1
+# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
+#endif /* __linux */
+
+#ifdef __sun
+# ifdef __sparc
+# include
+# else
+# include
+# include
+# endif /* __sparc */
+#endif /* __sun */
+
+
+/*
+ * 'get_device_id()' - Get the IEEE-1284 device ID string and
+ * corresponding URI.
+ */
+
+int /* O - 0 on success, -1 on failure */
+get_device_id(
+ int fd, /* I - File descriptor */
+ char *device_id, /* O - 1284 device ID */
+ int device_id_size, /* I - Size of buffer */
+ char *make_model, /* O - Make/model */
+ int make_model_size, /* I - Size of buffer */
+ const char *scheme, /* I - URI scheme */
+ char *uri, /* O - Device URI */
+ int uri_size) /* I - Size of buffer */
+{
+ char *attr, /* 1284 attribute */
+ *delim, /* 1284 delimiter */
+ *uriptr, /* Pointer into URI */
+ *mfg, /* Manufacturer string */
+ *mdl, /* Model string */
+ serial_number[1024]; /* Serial number string */
+#ifdef __linux
+ int length; /* Length of device ID info */
+#endif /* __linux */
+#ifdef __sun
+ struct ecpp_device_id did; /* Device ID buffer */
+#endif /* __sun */
+
+ DEBUG_printf(("get_device_id(fd=%d, device_id=%p, device_id_size=%d, "
+ "make_model=%p, make_model_size=%d, scheme=\"%s\", "
+ "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size,
+ make_model, make_model_size, scheme ? scheme : "(null)",
+ uri, uri_size));
+
+ /*
+ * Range check input...
+ */
+
+ if (fd < 0 ||
+ !device_id || device_id_size < 32 ||
+ !make_model || make_model_size < 32)
+ {
+ DEBUG_puts("get_device_id: Bad args!");
+ return (-1);
+ }
+
+ *device_id = '\0';
+ *make_model = '\0';
+
+ if (uri)
+ *uri = '\0';
+
+ /*
+ * Get the device ID string...
+ */
+
+#ifdef __linux
+ if (!ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
+ {
+ /*
+ * Extract the length of the device ID string from the first two
+ * bytes. The 1284 spec says the length is stored MSB first...
+ */
+
+ length = (((unsigned)device_id[0] & 255) << 8) +
+ ((unsigned)device_id[1] & 255);
+
+ /*
+ * Check to see if the length is larger than our buffer; first
+ * assume that the vendor incorrectly implemented the 1284 spec,
+ * and then limit the length to the size of our buffer...
+ */
+
+ if (length > (device_id_size - 2))
+ length = (((unsigned)device_id[1] & 255) << 8) +
+ ((unsigned)device_id[0] & 255);
+
+ if (length > (device_id_size - 2))
+ length = device_id_size - 2;
+
+ /*
+ * Copy the device ID text to the beginning of the buffer and
+ * nul-terminate.
+ */
+
+ memmove(device_id, device_id + 2, length);
+ device_id[length] = '\0';
+ }
+# ifdef DEBUG
+ else
+ printf("get_device_id: ioctl failed - %s\n", strerror(errno));
+# endif /* DEBUG */
+#endif /* __linux */
+
+#if defined(__sun) && defined(ECPPIOC_GETDEVID)
+ did.mode = ECPP_CENTRONICS;
+ did.len = device_id_size - 1;
+ did.rlen = 0;
+ did.addr = device_id;
+
+ if (!ioctl(fd, ECPPIOC_GETDEVID, &did))
+ {
+ /*
+ * Nul-terminate the device ID text.
+ */
+
+ if (did.rlen < (device_id_size - 1))
+ device_id[did.rlen] = '\0';
+ else
+ device_id[device_id_size - 1] = '\0';
+ }
+# ifdef DEBUG
+ else
+ printf("get_device_id: ioctl failed - %s\n", strerror(errno));
+# endif /* DEBUG */
+#endif /* __sun && ECPPIOC_GETDEVID */
+
+ DEBUG_printf(("get_device_id: device_id=\"%s\"\n", device_id));
+
+ if (!*device_id)
+ return (-1);
+
+ /*
+ * Look for the description field...
+ */
+
+ if ((attr = strstr(device_id, "DES:")) != NULL)
+ attr += 4;
+ else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
+ attr += 12;
+
+ if (attr)
+ {
+ /*
+ * Make sure the description contains something useful, since some
+ * printer manufacturers (HP) apparently don't follow the standards
+ * they helped to define...
+ *
+ * Here we require the description to be 8 or more characters in length,
+ * containing at least one space and one letter.
+ */
+
+ if ((delim = strchr(attr, ';')) == NULL)
+ delim = attr + strlen(attr);
+
+ if ((delim - attr) < 8)
+ attr = NULL;
+ else
+ {
+ char *ptr; /* Pointer into description */
+ int letters, /* Number of letters seen */
+ spaces; /* Number of spaces seen */
+
+
+ for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++)
+ {
+ if (isspace(*ptr & 255))
+ spaces ++;
+ else if (isalpha(*ptr & 255))
+ letters ++;
+
+ if (spaces && letters)
+ break;
+ }
+
+ if (!spaces || !letters)
+ attr = NULL;
+ }
+ }
+
+ if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
+ mfg += 13;
+ else if ((mfg = strstr(device_id, "MFG:")) != NULL)
+ mfg += 4;
+
+ if ((mdl = strstr(device_id, "MODEL:")) != NULL)
+ mdl += 6;
+ else if ((mdl = strstr(device_id, "MDL:")) != NULL)
+ mdl += 4;
+
+ if (attr)
+ {
+ /*
+ * Use description...
+ */
+
+ if (!strncasecmp(attr, "Hewlett-Packard hp ", 19))
+ {
+ /*
+ * Check for a common HP bug...
+ */
+
+ strlcpy(make_model, "HP ", make_model_size);
+ strlcpy(make_model + 3, attr + 19, make_model_size - 3);
+ }
+ else if (!strncasecmp(attr, "Hewlett-Packard ", 16))
+ {
+ strlcpy(make_model, "HP ", make_model_size);
+ strlcpy(make_model + 3, attr + 16, make_model_size - 3);
+ }
+ else
+ {
+ strlcpy(make_model, attr, make_model_size);
+ }
+ }
+ else if (mfg && mdl)
+ {
+ /*
+ * Build a make-model string from the manufacturer and model attributes...
+ */
+
+ if (!strncasecmp(mfg, "Hewlett-Packard", 15))
+ strlcpy(make_model, "HP", make_model_size);
+ else
+ strlcpy(make_model, mfg, make_model_size);
+
+ if ((delim = strchr(make_model, ';')) != NULL)
+ *delim = '\0';
+
+ if (!strncasecmp(make_model, mdl, strlen(make_model)))
+ {
+ /*
+ * Just copy model string, since it has the manufacturer...
+ */
+
+ strlcpy(make_model, mdl, make_model_size);
+ }
+ else
+ {
+ /*
+ * Concatenate the make and model...
+ */
+
+ strlcat(make_model, " ", make_model_size);
+ strlcat(make_model, mdl, make_model_size);
+ }
+ }
+ else
+ {
+ /*
+ * Use "Unknown" as the printer make and model...
+ */
+
+ strlcpy(make_model, "Unknown", make_model_size);
+ }
+
+ if ((delim = strchr(make_model, ';')) != NULL)
+ *delim = '\0';
+
+ if (scheme && uri && uri_size > 32)
+ {
+ /*
+ * Look for the serial number field...
+ */
+
+ if ((attr = strstr(device_id, "SERN:")) != NULL)
+ attr += 5;
+ else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
+ attr += 13;
+ else if ((attr = strstr(device_id, ";SN:")) != NULL)
+ attr += 4;
+
+ if (attr)
+ {
+ strlcpy(serial_number, attr, sizeof(serial_number));
+
+ if ((delim = strchr(serial_number, ';')) != NULL)
+ *delim = '\0';
+ }
+ else
+ serial_number[0] = '\0';
+
+ /*
+ * Generate the device URI from the make_model and serial number strings.
+ */
+
+ snprintf(uri, uri_size, "%s://", scheme);
+ for (uriptr = uri + strlen(uri), delim = make_model;
+ *delim && uriptr < (uri + uri_size - 1);
+ delim ++)
+ if (*delim == ' ')
+ {
+ delim ++;
+ *uriptr++ = '/';
+ break;
+ }
+ else
+ *uriptr++ = *delim;
+
+ for (; *delim && uriptr < (uri + uri_size - 3); delim ++)
+ if (*delim == ' ')
+ {
+ *uriptr++ = '%';
+ *uriptr++ = '2';
+ *uriptr++ = '0';
+ }
+ else
+ *uriptr++ = *delim;
+
+ *uriptr = '\0';
+
+ if (serial_number[0])
+ {
+ /*
+ * Add the serial number to the URI...
+ */
+
+ strlcat(uri, "?serial=", uri_size);
+ strlcat(uri, serial_number, uri_size);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $".
+ */
diff --git a/backend/ieee1394-linux.c b/backend/ieee1394-linux.c
new file mode 100644
index 000000000..b95e8204e
--- /dev/null
+++ b/backend/ieee1394-linux.c
@@ -0,0 +1,877 @@
+/*
+ * "$Id: ieee1394-linux.c 4703 2005-09-26 19:33:58Z mike $"
+ *
+ * Linux IEEE-1394 glue for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2002 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contents:
+ *
+ * get_device_id() - Get the IEEE-1284 device ID for a node...
+ * get_unit_type() - Get the unit type for a node...
+ * show_data() - Show a data node...
+ * show_dir() - Show a directory list...
+ * ieee1394_list() - List the available printer devices.
+ * ieee1394_open() - Open a printer device.
+ * ieee1394_close() - Close a printer device.
+ * ieee1394_read() - Read from a printer device.
+ * ieee1394_write() - Write data to a printer device.
+ * ieee1394_error() - Return the last error.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "ieee1394.h"
+#include
+#include
+#include
+
+
+/*
+ * Limits...
+ */
+
+#define MAX_NODES 100
+
+
+/*
+ * Structures...
+ */
+
+typedef struct
+{
+ char uri[HTTP_MAX_URI],/* URI for this node... */
+ description[128],/* Description of port */
+ make_model[128];/* Make and model */
+ int port, /* Port where this node is found */
+ node; /* Node number */
+ unsigned long long addr; /* Management address */
+} linux1394_node_t;
+
+typedef struct
+{
+ raw1394handle_t handle; /* Handle for printer device */
+ int node; /* Node number for printer device */
+ unsigned long long addr; /* Management address */
+} linux1394_dev_t;
+
+
+/*
+ * ORB messages for communication with the device...
+ */
+
+typedef struct /**** Login ORB Message */
+{
+ unsigned char passwd_addr[8]; /* Password address */
+ unsigned char resp_addr[8]; /* Login response address */
+ unsigned char notify_excl; /* Notify and exclusive bits */
+ unsigned char recon_func; /* Reconnect time and function */
+ unsigned char lun[2]; /* Logical unit number */
+ unsigned char passwd_len[2]; /* Length of password */
+ unsigned char resp_len[2]; /* Length of login response */
+ unsigned char fifo_addr[8]; /* Local status FIFO address */
+} login_orb_t;
+
+typedef struct /**** Login Response Message ****/
+{
+ unsigned char length[2]; /* Length of response */
+ unsigned char login_id[2]; /* Login ID */
+ unsigned char cmd_addr[8]; /* Command block agent address */
+ unsigned char reserved[2]; /* Reserved (0) */
+ unsigned char recon_hold[2]; /* Number of seconds to hold login */
+} login_resp_t;
+
+
+/*
+ * Local globals...
+ */
+
+static char error_string[1024] = "";
+static int num_nodes;
+static linux1394_node_t nodes[MAX_NODES];
+
+
+/*
+ * 'get_device_id()' - Get the IEEE-1284 device ID for a node...
+ */
+
+static char * /* O - Device ID */
+get_device_id(raw1394handle_t handle,/* I - Handle for device */
+ int node, /* I - Node number */
+ unsigned long long offset,/* I - Offset to directory */
+ char *id, /* O - ID string */
+ int idlen) /* I - Size of ID string */
+{
+ unsigned char data[1024], /* Data from ROM */
+ *dataptr; /* Pointer into data */
+ int length; /* Length of directory */
+ int datalen; /* Length of data */
+ unsigned long long dataoff; /* Offset of data */
+
+
+ DEBUG_printf(("get_device_id(handle = %p, node = %d, offset = %llx, id = %p, idlen = %d)\n",
+ handle, node, offset, id, idlen));
+
+ *id = '\0';
+
+ /*
+ * Read the directory length from the first quadlet...
+ */
+
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (NULL);
+
+ offset += 4;
+
+ /*
+ * The length is in the upper 16 bits...
+ */
+
+ length = (data[0] << 8) | data[1];
+
+ DEBUG_printf((" length = %d\n", length));
+
+ /*
+ * Then read the directory, looking for unit directory or device tags...
+ */
+
+ while (length > 0)
+ {
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (NULL);
+
+ DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1],
+ data[2], data[3]));
+
+ if (data[0] == 0xd1)
+ {
+ /*
+ * Found the unit directory...
+ */
+
+ offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2;
+
+ return (get_device_id(handle, node, offset, id, idlen));
+ }
+ else if (data[0] == 0x81)
+ {
+ /*
+ * Found potential IEEE-1284 device ID...
+ */
+
+ dataoff = offset + (((((data[1] << 8) | data[2]) << 8) | data[3]) << 2);
+
+ if (raw1394_read(handle, 0xffc0 | node, dataoff, 4, (quadlet_t *)data) < 0)
+ return (NULL);
+
+ dataoff += 4;
+
+ /*
+ * Read the leaf value...
+ */
+
+ datalen = (data[0] << 8) | data[1];
+
+ if (datalen > (sizeof(data) / 4))
+ datalen = sizeof(data) / 4;
+
+ for (dataptr = data; datalen > 0; datalen --, dataptr += 4, dataoff += 4)
+ if (raw1394_read(handle, 0xffc0 | node, dataoff, 4,
+ (quadlet_t *)dataptr) < 0)
+ return (NULL);
+
+ if (data[0] == 0 && memcmp(data + 8, "MFG:", 4) == 0)
+ {
+ /*
+ * Found the device ID...
+ */
+
+ datalen = dataptr - data - 8;
+ if (datalen >= idlen)
+ datalen --;
+
+ memcpy(id, data + 8, datalen);
+ id[datalen] = '\0';
+
+ return (id);
+ }
+ }
+
+ offset += 4;
+ length --;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'get_man_addr()' - Get the management address for a node...
+ */
+
+static int /* O - Unit type */
+get_man_addr(raw1394handle_t handle, /* I - Handle for device */
+ int node, /* I - Node number */
+ unsigned long long offset) /* I - Offset to directory */
+{
+ unsigned char data[4]; /* Data from ROM */
+ int length; /* Length of directory */
+
+
+ DEBUG_printf(("get_man_addr(handle = %p, node = %d, offset = %llx)\n",
+ handle, node, offset));
+
+ /*
+ * Read the directory length from the first quadlet...
+ */
+
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (-1);
+
+ offset += 4;
+
+ /*
+ * The length is in the upper 16 bits...
+ */
+
+ length = (data[0] << 8) | data[1];
+
+ DEBUG_printf((" length = %d\n", length));
+
+ /*
+ * Then read the directory, looking for unit directory or type tags...
+ */
+
+ while (length > 0)
+ {
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (-1);
+
+ DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1],
+ data[2], data[3]));
+
+ if (data[0] == 0xd1)
+ {
+ /*
+ * Found the unit directory...
+ */
+
+ offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2;
+
+ return (get_man_addr(handle, node, offset));
+ }
+ else if (data[0] == 0x54)
+ {
+ /*
+ * Found the management address...
+ */
+
+ return (((((data[1] << 8) | data[2]) << 8) | data[3]) << 2);
+ }
+
+ offset += 4;
+ length --;
+ }
+
+ return (-1);
+}
+
+
+/*
+ * 'get_unit_type()' - Get the unit type for a node...
+ */
+
+static int /* O - Unit type */
+get_unit_type(raw1394handle_t handle,/* I - Handle for device */
+ int node, /* I - Node number */
+ unsigned long long offset)/* I - Offset to directory */
+{
+ unsigned char data[4]; /* Data from ROM */
+ int length; /* Length of directory */
+
+
+ DEBUG_printf(("get_unit_type(handle = %p, node = %d, offset = %llx)\n",
+ handle, node, offset));
+
+ /*
+ * Read the directory length from the first quadlet...
+ */
+
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (-1);
+
+ offset += 4;
+
+ /*
+ * The length is in the upper 16 bits...
+ */
+
+ length = (data[0] << 8) | data[1];
+
+ DEBUG_printf((" length = %d\n", length));
+
+ /*
+ * Then read the directory, looking for unit directory or type tags...
+ */
+
+ while (length > 0)
+ {
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return (-1);
+
+ DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1],
+ data[2], data[3]));
+
+ if (data[0] == 0xd1)
+ {
+ /*
+ * Found the unit directory...
+ */
+
+ offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2;
+
+ return (get_unit_type(handle, node, offset));
+ }
+ else if (data[0] == 0x14)
+ {
+ /*
+ * Found the unit type...
+ */
+
+ return (data[1] & 0x1f);
+ }
+
+ offset += 4;
+ length --;
+ }
+
+ return (-1);
+}
+
+
+#ifdef DEBUG
+/*
+ * 'show_data()' - Show a data node...
+ */
+
+static void
+show_data(raw1394handle_t handle, /* I - Handle for device */
+ int node, /* I - Node number */
+ unsigned long long offset, /* I - Offset to directory */
+ int indent) /* Amount to indent */
+{
+ int i; /* Looping var */
+ unsigned char data[4]; /* Data from ROM */
+ int length; /* Length of data */
+
+
+ /*
+ * Read the data length from the first quadlet...
+ */
+
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return;
+
+ offset += 4;
+
+ /*
+ * The length is in the upper 16 bits...
+ */
+
+ length = (data[0] << 8) | data[1];
+
+ /*
+ * Then read the data...
+ */
+
+ for (i = 0; i < indent; i ++)
+ putchar(' ');
+
+ printf("LEAF (%d quadlets)\n", length);
+
+ while (length > 0)
+ {
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return;
+
+ for (i = 0; i < indent; i ++)
+ putchar(' ');
+
+ printf("%02X %02X %02X %02X '%c%c%c%c'\n",
+ data[0], data[1], data[2], data[3],
+ (data[0] < ' ' || data[0] >= 0x7f) ? '.' : data[0],
+ (data[1] < ' ' || data[1] >= 0x7f) ? '.' : data[1],
+ (data[2] < ' ' || data[2] >= 0x7f) ? '.' : data[2],
+ (data[3] < ' ' || data[3] >= 0x7f) ? '.' : data[3]);
+
+ offset += 4;
+ length --;
+ }
+}
+
+
+/*
+ * 'show_dir()' - Show a directory list...
+ */
+
+static void
+show_dir(raw1394handle_t handle, /* I - Handle for device */
+ int node, /* I - Node number */
+ unsigned long long offset, /* I - Offset to directory */
+ int indent) /* Amount to indent */
+{
+ int i; /* Looping var */
+ unsigned char data[4]; /* Data from ROM */
+ int length; /* Length of directory */
+ int value; /* Value in directory */
+
+
+ /*
+ * Read the directory length from the first quadlet...
+ */
+
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return;
+
+ offset += 4;
+
+ /*
+ * The length is in the upper 16 bits...
+ */
+
+ length = (data[0] << 8) | data[1];
+
+ /*
+ * Then read the directory...
+ */
+
+ while (length > 0)
+ {
+ if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0)
+ return;
+
+ for (i = 0; i < indent; i ++)
+ putchar(' ');
+
+ printf("%02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+
+ value = (((data[1] << 8) | data[2]) << 8) | data[3];
+
+ switch (data[0] & 0xc0)
+ {
+ case 0x00 :
+ for (i = -4; i < indent; i ++)
+ putchar(' ');
+
+ printf("IMMEDIATE %d\n", value);
+ break;
+
+ case 0x40 :
+ for (i = -4; i < indent; i ++)
+ putchar(' ');
+
+ printf("CSR OFFSET +%06X\n", value);
+ break;
+
+ case 0x80 :
+ show_data(handle, node, offset + value * 4, indent + 4);
+ break;
+
+ case 0xc0 :
+ show_dir(handle, node, offset + value * 4, indent + 4);
+ break;
+ }
+
+ offset += 4;
+ length --;
+ }
+}
+#endif /* DEBUG */
+
+
+/*
+ * 'ieee1394_list()' - List the available printer devices.
+ */
+
+ieee1394_info_t * /* O - Printer information */
+ieee1394_list(int *num_devices) /* O - Number of printers */
+{
+ int i, j; /* Looping vars */
+ raw1394handle_t handle; /* 1394 handle */
+ int num_ports; /* Number of ports */
+ struct raw1394_portinfo ports[100]; /* Port data... */
+ unsigned char guid[8]; /* Global unique ID */
+ int vendor; /* Vendor portion of GUID */
+ int unit_type; /* Unit type */
+ int addr; /* Management address offset */
+ char id[1024], /* Device ID string */
+ *idptr, /* Pointer into ID string */
+ *idsep; /* Pointer to separator */
+ ieee1394_info_t *devices; /* Device list */
+
+
+ /*
+ * Connect to the user-mode driver interface...
+ */
+
+ handle = raw1394_new_handle();
+ num_ports = raw1394_get_port_info(handle, ports,
+ sizeof(ports) / sizeof(ports[0]));
+
+ DEBUG_printf(("num_ports = %d\n", num_ports));
+
+ /*
+ * Loop through the ports to discover what nodes are available.
+ */
+
+ num_nodes = 0;
+
+ for (i = 0; i < num_ports; i ++)
+ {
+ DEBUG_printf(("ports[%d] = { nodes = %d, name = \"%s\" }\n", i,
+ ports[i].nodes, ports[i].name));
+
+ raw1394_set_port(handle, i);
+
+ for (j = 0; j < ports[i].nodes; j ++)
+ {
+ if (raw1394_read(handle, 0xffc0 | j,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM + 12, 4,
+ (quadlet_t *)guid) < 0)
+ {
+ DEBUG_printf((" Node #%d: Unable to contact (%s)!\n", j,
+ strerror(errno)));
+ continue;
+ }
+ else
+ {
+ raw1394_read(handle, 0xffc0 | j,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM + 16, 4,
+ (quadlet_t *)(guid + 4));
+
+ DEBUG_printf((" Node #%d: GUID = %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ j, guid[0], guid[1], guid[2], guid[3], guid[4],
+ guid[5], guid[6], guid[7]));
+
+ vendor = (((guid[0] << 8) | guid[1]) << 8) | guid[2];
+ unit_type = get_unit_type(handle, j,
+ CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20);
+
+ DEBUG_printf(("vendor = %x, unit_type = %d\n", vendor, unit_type));
+
+ if (unit_type == 2 && num_nodes < MAX_NODES)
+ {
+ /*
+ * Found a printer device; add it to the nodes list...
+ */
+
+#ifdef DEBUG
+ show_dir(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20, 0);
+#endif /* DEBUG */
+
+ memset(nodes + num_nodes, 0, sizeof(linux1394_node_t));
+
+ sprintf(nodes[num_nodes].uri, "ieee1394://%02X%02X%02X%02X%02X%02X%02X%02X",
+ guid[0], guid[1], guid[2], guid[3], guid[4],
+ guid[5], guid[6], guid[7]);
+
+ nodes[num_nodes].port = i;
+ nodes[num_nodes].node = j;
+
+ addr = get_man_addr(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20);
+
+ if (addr < 0)
+ continue;
+
+ nodes[num_nodes].addr = CSR_REGISTER_BASE + addr;
+
+ DEBUG_printf(("Node address = %llx\n", nodes[num_nodes].addr));
+
+ get_device_id(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20,
+ id, sizeof(id));
+
+ if (id[0])
+ {
+ /*
+ * Grab the manufacturer and model name from the device ID
+ * string...
+ */
+
+ idptr = id + 4;
+ idsep = strchr(id, ';');
+ if (idsep)
+ *idsep++ = '\0';
+ else
+ idsep = idptr;
+
+ snprintf(nodes[num_nodes].description,
+ sizeof(nodes[num_nodes].description),
+ "%s Firewire Printer", idptr);
+
+ if ((idptr = strstr(idsep, "DES:")) == NULL)
+ idptr = strstr(idsep, "MDL:");
+
+ if (idptr == NULL)
+ strcpy(nodes[num_nodes].make_model, "Unknown");
+ else
+ {
+ /*
+ * Grab the DES or MDL code...
+ */
+
+ idptr += 4;
+ idsep = strchr(idptr, ';');
+ if (idsep)
+ *idsep = '\0';
+
+ if (strncmp(id + 4, idptr, strlen(id + 4)) == 0)
+ {
+ /*
+ * Use the description directly...
+ */
+
+ strlcpy(nodes[num_nodes].make_model, idptr,
+ sizeof(nodes[num_nodes].make_model));
+ }
+ else
+ {
+ /*
+ * Add the manufacturer to the front of the name...
+ */
+
+ snprintf(nodes[num_nodes].make_model,
+ sizeof(nodes[num_nodes].make_model),
+ "%s %s", id + 4, idptr);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Flag it as an unknown printer...
+ */
+
+ sprintf(nodes[num_nodes].description,
+ "Unknown%06X Firewire Printer", vendor);
+ strcpy(nodes[num_nodes].make_model, "Unknown");
+ }
+
+ num_nodes ++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Done querying the Firewire bus...
+ */
+
+ raw1394_destroy_handle(handle);
+
+ /*
+ * Build an array of device info structures as needed...
+ */
+
+ if (num_devices == NULL)
+ return (NULL);
+
+ *num_devices = num_nodes;
+
+ if (num_nodes)
+ {
+ if ((devices = calloc(sizeof(ieee1394_info_t), num_nodes)) != NULL)
+ {
+ for (i = 0; i < num_nodes; i ++)
+ {
+ strcpy(devices[i].uri, nodes[i].uri);
+ strcpy(devices[i].description, nodes[i].description);
+ strcpy(devices[i].make_model, nodes[i].make_model);
+ }
+ }
+
+ return (devices);
+ }
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'ieee1394_open()' - Open a printer device.
+ */
+
+ieee1394_dev_t /* O - Printer device or NULL */
+ieee1394_open(const char *uri) /* I - Device URI */
+{
+ int i; /* Looping var */
+ linux1394_dev_t *ldev; /* Linux device */
+
+
+ /*
+ * Return early if we can't see any printers...
+ */
+
+ if (num_nodes == 0)
+ ieee1394_list(NULL);
+
+ if (num_nodes == 0)
+ {
+ strcpy(error_string, "No IEEE-1394 printers found!");
+ return (NULL);
+ }
+
+ /*
+ * Look for the URI...
+ */
+
+ for (i = 0; i < num_nodes; i ++)
+ if (strcmp(nodes[i].uri, uri) == 0)
+ break;
+
+ if (i >= num_nodes)
+ {
+ snprintf(error_string, sizeof(error_string), "Device %s not found!", uri);
+ return (NULL);
+ }
+
+ /*
+ * Now create a new device structure...
+ */
+
+ if ((ldev = calloc(sizeof(linux1394_dev_t), 1)) == NULL)
+ {
+ strcpy(error_string, "Out of memory!");
+ return (NULL);
+ }
+
+ ldev->handle = raw1394_new_handle();
+ ldev->node = nodes[i].node;
+ ldev->addr = nodes[i].addr;
+
+ raw1394_set_port(ldev->handle, nodes[i].port);
+
+ error_string[0] = '\0';
+
+ return ((ieee1394_dev_t)ldev);
+}
+
+
+/*
+ * 'ieee1394_close()' - Close a printer device.
+ */
+
+int /* O - 0 on success, -1 on failure */
+ieee1394_close(ieee1394_dev_t dev) /* I - Printer device */
+{
+ linux1394_dev_t *ldev; /* Linux device */
+
+
+ ldev = (linux1394_dev_t *)dev;
+
+ raw1394_destroy_handle(ldev->handle);
+
+ free(ldev);
+
+ return (0);
+}
+
+
+/*
+ * 'ieee1394_read()' - Read from a printer device.
+ */
+
+int /* O - Number of bytes read or -1 */
+ieee1394_read(ieee1394_dev_t dev, /* I - Printer device */
+ char *buffer, /* I - Read buffer */
+ int len) /* I - Max bytes to read */
+{
+ linux1394_dev_t *ldev; /* Linux device */
+
+
+ ldev = (linux1394_dev_t *)dev;
+
+
+ return (0);
+}
+
+
+/*
+ * 'ieee1394_write()' - Write data to a printer device.
+ */
+
+int /* O - Number of bytes written or -1 */
+ieee1394_write(ieee1394_dev_t dev, /* I - Printer device */
+ char *buffer, /* I - Buffer to write */
+ int len) /* I - Number of bytes to write */
+{
+ linux1394_dev_t *ldev; /* Linux device */
+
+
+ ldev = (linux1394_dev_t *)dev;
+
+
+/* if (raw1394_write(handle, 0xffc0 | j, 0, ,
+ (quadlet_t *)guid) < 0)*/
+
+ return (len);
+}
+
+
+/*
+ * 'ieee1394_error()' - Return the last error.
+ */
+
+const char * /* O - Error string or NULL */
+ieee1394_error(void)
+{
+ if (error_string[0])
+ return (error_string);
+ else
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id: ieee1394-linux.c 4703 2005-09-26 19:33:58Z mike $".
+ */
diff --git a/backend/ieee1394.c b/backend/ieee1394.c
new file mode 100644
index 000000000..0be210581
--- /dev/null
+++ b/backend/ieee1394.c
@@ -0,0 +1,263 @@
+/*
+ * "$Id: ieee1394.c 4494 2005-02-18 02:18:11Z mike $"
+ *
+ * IEEE-1394 backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2002 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contents:
+ *
+ * main() - Send a file to the printer.
+ * list_devices() - List all known printer devices...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "ieee1394.h"
+
+
+/*
+ * Local functions...
+ */
+
+void list_devices(void);
+
+
+/*
+ * 'main()' - Send a file to the printer.
+ *
+ * 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 */
+{
+ ieee1394_dev_t dev; /* Printer device */
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int rbytes; /* Number of bytes read from device */
+ size_t nbytes, /* Number of bytes read from file */
+ tbytes; /* Total number of bytes written */
+ char buffer[8192]; /* Input/output buffer */
+#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)
+ {
+ 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 = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: unable to open print file");
+ return (1);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Try to open the printer device...
+ */
+
+ do
+ {
+ if ((dev = ieee1394_open(argv[0])) == NULL)
+ {
+ fputs("INFO: Firewire printer busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ }
+ while (dev == NULL);
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#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 != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(fp, 0, SEEK_SET);
+ }
+
+ tbytes = 0;
+ while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+
+ if (ieee1394_write(dev, buffer, nbytes) < 0)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+
+ if ((rbytes = ieee1394_read(dev, buffer, sizeof(buffer))) > 0)
+ fprintf(stderr, "INFO: Read %d bytes from printer...\n", rbytes);
+
+ if (argc > 6)
+ fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
+ (unsigned long)tbytes);
+ }
+ }
+
+ /*
+ * Close the printer device and input file and return...
+ */
+
+ ieee1394_close(dev);
+
+ if (fp != 0)
+ close(fp);
+
+ fputs("INFO: Ready to print.\n", stderr);
+
+ return (0);
+}
+
+
+/*
+ * 'list_devices()' - List all known devices...
+ */
+
+void
+list_devices(void)
+{
+ int i, /* Looping var */
+ num_info; /* Number of devices */
+ ieee1394_info_t *info; /* Devices... */
+
+
+ /*
+ * Get the available devices...
+ */
+
+ info = ieee1394_list(&num_info);
+
+ /*
+ * List them as needed...
+ */
+
+ if (num_info > 0)
+ {
+ for (i = 0; i < num_info; i ++)
+ printf("direct %s \"%s\" \"%s\"\n", info[i].uri,
+ info[i].make_model, info[i].description);
+
+ free(info);
+ }
+}
+
+
+/*
+ * End of "$Id: ieee1394.c 4494 2005-02-18 02:18:11Z mike $".
+ */
diff --git a/backend/ieee1394.h b/backend/ieee1394.h
new file mode 100644
index 000000000..19181c5c0
--- /dev/null
+++ b/backend/ieee1394.h
@@ -0,0 +1,103 @@
+/*
+ * "$Id: ieee1394.h 4494 2005-02-18 02:18:11Z mike $"
+ *
+ * IEEE-1394 header for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2002 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+#endif /* WIN32 */
+
+
+/*
+ * Device information structure...
+ */
+
+typedef struct
+{
+ char uri[HTTP_MAX_URI], /* Device URI */
+ description[128], /* Description of port */
+ make_model[128]; /* Make and model */
+} ieee1394_info_t;
+
+
+/*
+ * Private device connection information...
+ */
+
+typedef void *ieee1394_dev_t;
+
+
+/*
+ * Prototypes for standard IEEE-1394 interface...
+ */
+
+extern ieee1394_info_t *ieee1394_list(int *num_devices);
+extern ieee1394_dev_t ieee1394_open(const char *uri);
+extern int ieee1394_close(ieee1394_dev_t dev);
+extern int ieee1394_read(ieee1394_dev_t dev, char *buffer, int len);
+extern int ieee1394_write(ieee1394_dev_t dev, char *buffer, int len);
+extern const char *ieee1394_error(void);
+
+
+/*
+ * End of "$Id: ieee1394.h 4494 2005-02-18 02:18:11Z mike $".
+ */
diff --git a/backend/ipp.c b/backend/ipp.c
new file mode 100644
index 000000000..47cee2b91
--- /dev/null
+++ b/backend/ipp.c
@@ -0,0 +1,1468 @@
+/*
+ * "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * IPP backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Send a file to the printer or server.
+ * check_printer_state() - Check the printer state...
+ * password_cb() - Disable the password prompt for
+ * cupsDoFileRequest().
+ * report_printer_state() - Report the printer state.
+ * run_pictwps_filter() - Convert PICT files to PostScript when printing
+ * remotely.
+ * sigterm_handler() - Handle 'terminate' signals that stop the backend.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/*
+ * Globals...
+ */
+
+static char *password = NULL; /* Password for device URI */
+#ifdef __APPLE__
+static char pstmpname[1024] = ""; /* Temporary PostScript file name */
+#endif /* __APPLE__ */
+static char tmpfilename[1024] = ""; /* Temporary spool file name */
+
+
+/*
+ * Local functions...
+ */
+
+void check_printer_state(http_t *http, cups_lang_t *language,
+ const char *charset, const char *uri, /* I - Printer URI */
+ const char *resource, const char *user,
+ int version);
+const char *password_cb(const char *);
+int report_printer_state(ipp_t *ipp);
+
+#ifdef __APPLE__
+int run_pictwps_filter(char **argv, const char *filename);
+#endif /* __APPLE__ */
+static void sigterm_handler(int sig);
+
+
+/*
+ * '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) */
+ *optptr, /* Pointer to URI options */
+ name[255], /* Name of option */
+ value[255], /* Value of option */
+ *ptr; /* Pointer into name or value */
+ char *filename; /* 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 */
+ int waitjob, /* Wait for job complete? */
+ waitprinter; /* Wait for printer ready? */
+ ipp_attribute_t *job_id_attr; /* job-id attribute */
+ int job_id; /* job-id value */
+ ipp_attribute_t *job_sheets; /* job-media-sheets-completed attribute */
+ 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 */
+ ipp_attribute_t *printer_state; /* printer-state attribute */
+ ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs 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 */
+ int reasons; /* Number of printer-state-reasons shown */
+ static const char * const pattrs[] =
+ { /* Printer attributes we want */
+ "copies-supported",
+ "charset-supported",
+ "document-format-supported",
+ "printer-is-accepting-jobs",
+ "printer-state",
+ "printer-state-reasons",
+ };
+ static const char * const jattrs[] =
+ { /* Job attributes we want */
+ "job-media-sheets-completed",
+ "job-state"
+ };
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore SIGPIPE and catch SIGTERM signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * 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 (%s)\"\n", s, s);
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
+ argv[0]);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Get the content type...
+ */
+
+ if (argc > 6)
+ content_type = getenv("CONTENT_TYPE");
+ else
+ content_type = "application/vnd.cups-raw";
+
+ if (content_type == NULL)
+ content_type = "application/octet-stream";
+
+ /*
+ * Extract the hostname and printer name from the URI...
+ */
+
+ if (getenv("DEVICE_URI") != NULL)
+ /* authentication information is only available in the env var */
+ httpSeparateURI(getenv("DEVICE_URI"), method, sizeof(method),
+ username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+ else if (strchr(argv[0], ':') != NULL)
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+ else
+ {
+ fputs("ERROR: Missing device URI on command-line and no DEVICE_URI environment variable!\n",
+ stderr);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ if (!strcmp(method, "https"))
+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
+
+ /*
+ * 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(tmpfilename, sizeof(tmpfilename))) < 0)
+ {
+ perror("ERROR: unable to create temporary file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ 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(tmpfilename);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ close(fd);
+ filename = tmpfilename;
+ }
+ else
+ filename = argv[6];
+
+ /*
+ * See if there are any options...
+ */
+
+ version = 1;
+ waitjob = 1;
+ waitprinter = 1;
+
+ if ((optptr = strchr(resource, '?')) != NULL)
+ {
+ /*
+ * Yup, terminate the device name string and move to the first
+ * character of the optptr...
+ */
+
+ *optptr++ = '\0';
+
+ /*
+ * Then parse the optptr...
+ */
+
+ while (*optptr)
+ {
+ /*
+ * Get the name...
+ */
+
+ for (ptr = name; *optptr && *optptr != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *optptr++;
+ *ptr = '\0';
+
+ if (*optptr == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ optptr ++;
+
+ for (ptr = value; *optptr && *optptr != '+' && *optptr != '&';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *optptr++;
+ *ptr = '\0';
+
+ if (*optptr == '+')
+ optptr ++;
+ }
+ else
+ value[0] = '\0';
+
+ /*
+ * Process the option...
+ */
+
+ if (!strcasecmp(name, "waitjob"))
+ {
+ /*
+ * Wait for job completion?
+ */
+
+ waitjob = !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "true");
+ }
+ else if (!strcasecmp(name, "waitprinter"))
+ {
+ /*
+ * Wait for printer idle?
+ */
+
+ waitprinter = !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "true");
+ }
+ else if (!strcasecmp(name, "encryption"))
+ {
+ /*
+ * Enable/disable encryption?
+ */
+
+ if (!strcasecmp(value, "always"))
+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
+ else if (!strcasecmp(value, "required"))
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+ else if (!strcasecmp(value, "never"))
+ cupsSetEncryption(HTTP_ENCRYPT_NEVER);
+ else if (!strcasecmp(value, "ifrequested"))
+ cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
+ else
+ {
+ fprintf(stderr, "ERROR: Unknown encryption option value \"%s\"!\n",
+ value);
+ }
+ }
+ else if (!strcasecmp(name, "version"))
+ {
+ if (!strcmp(value, "1.0"))
+ version = 0;
+ else if (!strcmp(value, "1.1"))
+ version = 1;
+ else
+ {
+ fprintf(stderr, "ERROR: Unknown version option value \"%s\"!\n",
+ value);
+ }
+ }
+ else
+ {
+ /*
+ * Unknown option...
+ */
+
+ fprintf(stderr, "ERROR: Unknown option \"%s\" with value \"%s\"!\n",
+ name, value);
+ }
+ }
+ }
+
+ /*
+ * Set the authentication info, if any...
+ */
+
+ cupsSetPasswordCB(password_cb);
+
+ if (username[0])
+ {
+ /*
+ * Use authenticaion information in the device URI...
+ */
+
+ if ((password = strchr(username, ':')) != NULL)
+ *password++ = '\0';
+
+ cupsSetUser(username);
+ }
+ else if (!getuid())
+ {
+ /*
+ * Try loading authentication information from the a##### file.
+ */
+
+ const char *request_root; /* CUPS_REQUESTROOT env var */
+ char afilename[1024], /* a##### filename */
+ aline[1024]; /* Line from file */
+ FILE *fp; /* File pointer */
+
+
+ if ((request_root = getenv("CUPS_REQUESTROOT")) != NULL)
+ {
+ /*
+ * Try opening authentication cache file...
+ */
+
+ snprintf(afilename, sizeof(afilename), "%s/a%05d", request_root,
+ atoi(argv[1]));
+ if ((fp = fopen(afilename, "r")) != NULL)
+ {
+ /*
+ * Read username...
+ */
+
+ if (fgets(aline, sizeof(aline), fp))
+ {
+ /*
+ * Decode username...
+ */
+
+ i = sizeof(username);
+ httpDecode64_2(username, &i, aline);
+
+ /*
+ * Read password...
+ */
+
+ if (fgets(aline, sizeof(aline), fp))
+ {
+ /*
+ * Decode password...
+ */
+
+ i = sizeof(password);
+ httpDecode64_2(password, &i, aline);
+ }
+ }
+
+ /*
+ * Close the file...
+ */
+
+ fclose(fp);
+ }
+ }
+ }
+
+ /*
+ * Try connecting to the remote server...
+ */
+
+ do
+ {
+ fprintf(stderr, "INFO: Connecting to %s on port %d...\n", hostname, port);
+
+ if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL)
+ {
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n",
+ hostname);
+
+ if (argc == 6 || strcmp(filename, argv[6]))
+ unlink(filename);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
+ errno == EHOSTUNREACH)
+ {
+ fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...\n",
+ hostname);
+ sleep(30);
+ }
+ else if (h_errno)
+ {
+ fprintf(stderr, "INFO: Unable to lookup host \'%s\' - %s\n",
+ hostname, hstrerror(h_errno));
+ sleep(30);
+ }
+ else
+ {
+ perror("ERROR: Unable to connect to IPP host");
+ sleep(30);
+ }
+ }
+ }
+ while (http == NULL);
+
+ fprintf(stderr, "INFO: Connected to %s...\n", hostname);
+
+ /*
+ * 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;
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request...
+ */
+
+ fputs("DEBUG: Getting supported attributes...\n", stderr);
+
+ 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 (ipp_status == IPP_PRINTER_BUSY ||
+ ipp_status == IPP_SERVICE_UNAVAILABLE)
+ {
+ fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr);
+ report_printer_state(supported);
+ 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;
+ httpReconnect(http);
+ }
+ else if (ipp_status == IPP_NOT_FOUND)
+ {
+ fputs("ERROR: Destination printer does not exist!\n", stderr);
+
+ if (supported)
+ ippDelete(supported);
+
+ return (CUPS_BACKEND_STOP);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to get printer status (%s)!\n",
+ ippErrorString(ipp_status));
+ sleep(10);
+ }
+
+ if (supported)
+ ippDelete(supported);
+
+ continue;
+ }
+ 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);
+ }
+
+ report_printer_state(supported);
+ }
+ while (ipp_status > IPP_OK_CONFLICT);
+
+ /*
+ * See if the printer is accepting jobs and is not stopped; if either
+ * condition is true and we are printing to a class, requeue the job...
+ */
+
+ if (getenv("CLASS") != NULL)
+ {
+ printer_state = ippFindAttribute(supported, "printer-state",
+ IPP_TAG_ENUM);
+ printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN);
+
+ if (printer_state == NULL ||
+ (printer_state->values[0].integer > IPP_PRINTER_PROCESSING && waitprinter) ||
+ printer_accepting == NULL ||
+ !printer_accepting->values[0].boolean)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fprintf(stderr, "INFO: Unable to queue job on %s, queuing on next printer in class...\n",
+ hostname);
+
+ ippDelete(supported);
+ httpClose(http);
+
+ if (argc == 6 || strcmp(filename, argv[6]))
+ unlink(filename);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ /*
+ * See if the printer supports multiple copies...
+ */
+
+ if (copies_sup || argc < 7)
+ 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...
+ */
+
+ reasons = 0;
+
+ 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);
+
+ if (argv[2][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, argv[2]);
+
+ fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
+
+ if (argv[3][0])
+ 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);
+
+#ifdef __APPLE__
+ if (content_type != NULL && strcasecmp(content_type, "application/pictwps") == 0)
+ {
+ if (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 (format_sup == NULL || i >= format_sup->num_values)
+ {
+ /*
+ * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
+ * so convert the document to PostScript...
+ */
+
+ if (run_pictwps_filter(argv, filename))
+ return (CUPS_BACKEND_FAILED);
+
+ filename = pstmpname;
+
+ /*
+ * Change the MIME type to application/postscript...
+ */
+
+ content_type = "application/postscript";
+ }
+ }
+#endif /* __APPLE__ */
+
+ if (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);
+ }
+
+ if (copies_sup)
+ {
+ /*
+ * Only send options if the destination printer supports the copies
+ * attribute. This is a hack for the HP JetDirect implementation of
+ * IPP, which does not accept extension attributes and incorrectly
+ * reports a client-error-bad-request error instead of the
+ * successful-ok-unsupported-attributes status. In short, at least
+ * some HP implementations of IPP are non-compliant.
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
+ atoi(argv[4]));
+ }
+
+ cupsFreeOptions(num_options, options);
+
+ /*
+ * If copies aren't supported, then we are likely dealing with an HP
+ * JetDirect. The HP IPP implementation seems to close the connection
+ * after every request (that is, it does *not* implement HTTP Keep-
+ * Alive, which is REQUIRED by HTTP/1.1...
+ */
+
+ if (!copies_sup)
+ httpReconnect(http);
+
+ /*
+ * 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)
+ {
+ job_id = 0;
+
+ 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("NOTICE: Print file accepted - job ID unknown.\n", stderr);
+ job_id = 0;
+ }
+ else
+ {
+ job_id = job_id_attr->values[0].integer;
+ fprintf(stderr, "NOTICE: Print file accepted - job ID %d.\n", job_id);
+ }
+
+ if (response)
+ ippDelete(response);
+
+ if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
+ {
+ 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;
+ else
+ copies --;
+
+ /*
+ * Wait for the job to complete...
+ */
+
+ if (!job_id || !waitjob)
+ 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);
+
+ if (argv[2][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, argv[2]);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
+ NULL, jattrs);
+
+ /*
+ * Do the request...
+ */
+
+ if (!copies_sup)
+ httpReconnect(http);
+
+ if ((response = cupsDoRequest(http, request, resource)) == NULL)
+ ipp_status = cupsLastError();
+ else
+ ipp_status = response->request.status.status_code;
+
+ if (ipp_status == IPP_NOT_FOUND)
+ {
+ /*
+ * Job has gone away and/or the server has no job history...
+ */
+
+ ippDelete(response);
+
+ ipp_status = IPP_OK;
+ break;
+ }
+
+ 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;
+ }
+ }
+
+ if (response != NULL)
+ {
+ if ((job_state = ippFindAttribute(response, "job-state",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ /*
+ * Stop polling if the job is finished or pending-held...
+ */
+
+ if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
+ job_state->values[0].integer == IPP_JOB_HELD)
+ {
+ if ((job_sheets = ippFindAttribute(response, "job-media-sheets-completed",
+ IPP_TAG_INTEGER)) != NULL)
+ fprintf(stderr, "PAGE: total %d\n", job_sheets->values[0].integer);
+
+ ippDelete(response);
+ break;
+ }
+ }
+ }
+
+ if (response)
+ ippDelete(response);
+
+ /*
+ * Check the printer state and report it if necessary...
+ */
+
+/* if (!copies_sup)
+ httpReconnect(http);*/
+
+ check_printer_state(http, language, charset, uri, resource, argv[2],
+ version);
+
+ /*
+ * Wait 10 seconds before polling again...
+ */
+
+ sleep(10);
+ }
+ }
+
+ /*
+ * Check the printer state and report it if necessary...
+ */
+
+/* if (!copies_sup)
+ httpReconnect(http);*/
+
+ check_printer_state(http, language, charset, uri, resource, argv[2], version);
+
+ /*
+ * Free memory...
+ */
+
+ httpClose(http);
+
+ if (supported)
+ ippDelete(supported);
+
+ /*
+ * Remove the temporary file(s) if necessary...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+#ifdef __APPLE__
+ if (pstmpname[0])
+ unlink(pstmpname);
+#endif /* __APPLE__ */
+
+ /*
+ * Return the queue status...
+ */
+
+ return (ipp_status > IPP_OK_CONFLICT ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'check_printer_state()' - Check the printer state...
+ */
+
+void
+check_printer_state(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language,
+ /* I - Language */
+ const char *charset,
+ /* I - Charset */
+ const char *uri, /* I - Printer URI */
+ const char *resource,
+ /* I - Resource path */
+ const char *user, /* I - Username, if any */
+ int version)/* I - IPP version */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+
+
+ /*
+ * Check on the printer state...
+ */
+
+ 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, 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);
+
+ if (user && user[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-state-reasons");
+
+ /*
+ * Do the request...
+ */
+
+ if ((response = cupsDoRequest(http, request, resource)) != NULL)
+ {
+ report_printer_state(response);
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
+ */
+
+const char * /* O - Password */
+password_cb(const char *prompt) /* I - Prompt (not used) */
+{
+ (void)prompt;
+
+ if (password)
+ return (password);
+ else
+ {
+ /*
+ * If there is no password set in the device URI, return the
+ * "authentication required" exit code...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+#ifdef __APPLE__
+ if (pstmpname[0])
+ unlink(pstmpname);
+#endif /* __APPLE__ */
+
+ exit(CUPS_BACKEND_AUTH_REQUIRED);
+ }
+}
+
+
+/*
+ * 'report_printer_state()' - Report the printer state.
+ */
+
+int /* O - Number of reasons shown */
+report_printer_state(ipp_t *ipp) /* I - IPP response */
+{
+ int i; /* Looping var */
+ int count; /* Count of reasons shown... */
+ ipp_attribute_t *reasons; /* printer-state-reasons */
+ const char *reason; /* Current reason */
+ const char *message; /* Message to show */
+ char unknown[1024]; /* Unknown message string */
+ const char *prefix; /* Prefix for STATE: line */
+ char state[1024]; /* State string */
+
+
+ if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
+ IPP_TAG_KEYWORD)) == NULL)
+ return (0);
+
+ state[0] = '\0';
+ prefix = "STATE: ";
+
+ for (i = 0, count = 0; i < reasons->num_values; i ++)
+ {
+ reason = reasons->values[i].string.text;
+
+ strlcat(state, prefix, sizeof(state));
+ strlcat(state, reason, sizeof(state));
+
+ prefix = ",";
+ message = NULL;
+
+ if (!strncmp(reason, "media-needed", 12))
+ message = "Media tray needs to be filled.";
+ else if (!strncmp(reason, "media-jam", 9))
+ message = "Media jam!";
+ else if (!strncmp(reason, "moving-to-paused", 16) ||
+ !strncmp(reason, "paused", 6) ||
+ !strncmp(reason, "shutdown", 8))
+ message = "Printer off-line.";
+ else if (!strncmp(reason, "toner-low", 9))
+ message = "Toner low.";
+ else if (!strncmp(reason, "toner-empty", 11))
+ message = "Out of toner!";
+ else if (!strncmp(reason, "cover-open", 10))
+ message = "Cover open.";
+ else if (!strncmp(reason, "interlock-open", 14))
+ message = "Interlock open.";
+ else if (!strncmp(reason, "door-open", 9))
+ message = "Door open.";
+ else if (!strncmp(reason, "input-tray-missing", 18))
+ message = "Media tray missing!";
+ else if (!strncmp(reason, "media-low", 9))
+ message = "Media tray almost empty.";
+ else if (!strncmp(reason, "media-empty", 11))
+ message = "Media tray empty!";
+ else if (!strncmp(reason, "output-tray-missing", 19))
+ message = "Output tray missing!";
+ else if (!strncmp(reason, "output-area-almost-full", 23))
+ message = "Output bin almost full.";
+ else if (!strncmp(reason, "output-area-full", 16))
+ message = "Output bin full!";
+ else if (!strncmp(reason, "marker-supply-low", 17))
+ message = "Ink/toner almost empty.";
+ else if (!strncmp(reason, "marker-supply-empty", 19))
+ message = "Ink/toner empty!";
+ else if (!strncmp(reason, "marker-waste-almost-full", 24))
+ message = "Ink/toner waste bin almost full.";
+ else if (!strncmp(reason, "marker-waste-full", 17))
+ message = "Ink/toner waste bin full!";
+ else if (!strncmp(reason, "fuser-over-temp", 15))
+ message = "Fuser temperature high!";
+ else if (!strncmp(reason, "fuser-under-temp", 16))
+ message = "Fuser temperature low!";
+ else if (!strncmp(reason, "opc-near-eol", 12))
+ message = "OPC almost at end-of-life.";
+ else if (!strncmp(reason, "opc-life-over", 13))
+ message = "OPC at end-of-life!";
+ else if (!strncmp(reason, "developer-low", 13))
+ message = "Developer almost empty.";
+ else if (!strncmp(reason, "developer-empty", 15))
+ message = "Developer empty!";
+ else if (strstr(reason, "error") != NULL)
+ {
+ message = unknown;
+
+ snprintf(unknown, sizeof(unknown), "Unknown printer error (%s)!",
+ reason);
+ }
+
+ if (message)
+ {
+ count ++;
+ if (strstr(reasons->values[i].string.text, "error"))
+ fprintf(stderr, "ERROR: %s\n", message);
+ else if (strstr(reasons->values[i].string.text, "warning"))
+ fprintf(stderr, "WARNING: %s\n", message);
+ else
+ fprintf(stderr, "INFO: %s\n", message);
+ }
+ }
+
+ fprintf(stderr, "%s\n", state);
+
+ return (count);
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
+ * remotely.
+ *
+ * This step is required because the PICT format is not documented and
+ * subject to change, so developing a filter for other OS's is infeasible.
+ * Also, fonts required by the PICT file need to be embedded on the
+ * client side (which has the fonts), so we run the filter to get a
+ * PostScript file for printing...
+ */
+
+int /* O - Exit status of filter */
+run_pictwps_filter(char **argv, /* I - Command-line arguments */
+ const char *filename) /* I - Filename */
+{
+ struct stat fileinfo; /* Print file information */
+ const char *ppdfile; /* PPD file for destination printer */
+ int pid; /* Child process ID */
+ int fd; /* Temporary file descriptor */
+ int status; /* Exit status of filter */
+ const char *printer; /* PRINTER env var */
+ static char ppdenv[1024]; /* PPD environment variable */
+
+
+ /*
+ * First get the PPD file for the printer...
+ */
+
+ printer = getenv("PRINTER");
+ if (!printer)
+ {
+ fputs("ERROR: PRINTER environment variable not defined!\n", stderr);
+ return (-1);
+ }
+
+ if ((ppdfile = cupsGetPPD(printer)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n",
+ printer, ippErrorString(cupsLastError()));
+ /*return (-1);*/
+ }
+ else
+ {
+ snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile);
+ putenv(ppdenv);
+ }
+
+ /*
+ * Then create a temporary file for printing...
+ */
+
+ if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0)
+ {
+ fprintf(stderr, "ERROR: Unable to create temporary file - %s.\n",
+ strerror(errno));
+ if (ppdfile)
+ unlink(ppdfile);
+ return (-1);
+ }
+
+ /*
+ * Get the owner of the spool file - it is owned by the user we want to run
+ * as...
+ */
+
+ if (argv[6])
+ stat(argv[6], &fileinfo);
+ else
+ {
+ /*
+ * Use the OSX defaults, as an up-stream filter created the PICT
+ * file...
+ */
+
+ fileinfo.st_uid = 1;
+ fileinfo.st_gid = 80;
+ }
+
+ if (ppdfile)
+ chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid);
+
+ fchown(fd, fileinfo.st_uid, fileinfo.st_gid);
+
+ /*
+ * Finally, run the filter to convert the file...
+ */
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child process for pictwpstops... Redirect output of pictwpstops to a
+ * file...
+ */
+
+ close(1);
+ dup(fd);
+ close(fd);
+
+ if (!getuid())
+ {
+ /*
+ * Change to an unpriviledged user...
+ */
+
+ setgid(fileinfo.st_gid);
+ setuid(fileinfo.st_uid);
+ }
+
+ execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5],
+ filename, NULL);
+ perror("ERROR: Unable to exec pictwpstops");
+ return (errno);
+ }
+
+ close(fd);
+
+ if (pid < 0)
+ {
+ /*
+ * Error!
+ */
+
+ perror("ERROR: Unable to fork pictwpstops");
+ unlink(filename);
+ if (ppdfile)
+ unlink(ppdfile);
+ return (-1);
+ }
+
+ /*
+ * Now wait for the filter to complete...
+ */
+
+ if (wait(&status) < 0)
+ {
+ perror("ERROR: Unable to wait for pictwpstops");
+ close(fd);
+ unlink(filename);
+ if (ppdfile)
+ unlink(ppdfile);
+ return (-1);
+ }
+
+ if (ppdfile)
+ unlink(ppdfile);
+
+ close(fd);
+
+ if (status)
+ {
+ if (status >= 256)
+ fprintf(stderr, "ERROR: pictwpstops exited with status %d!\n",
+ status / 256);
+ else
+ fprintf(stderr, "ERROR: pictwpstops exited on signal %d!\n",
+ status);
+
+ unlink(filename);
+ return (status);
+ }
+
+ /*
+ * Return with no errors..
+ */
+
+ return (0);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal */
+{
+ (void)sig; /* remove compiler warnings... */
+
+ /*
+ * Remove the temporary file(s) if necessary...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+#ifdef __APPLE__
+ if (pstmpname[0])
+ unlink(pstmpname);
+#endif /* __APPLE__ */
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/lpd.c b/backend/lpd.c
new file mode 100644
index 000000000..ee6d3deaa
--- /dev/null
+++ b/backend/lpd.c
@@ -0,0 +1,1149 @@
+/*
+ * "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * 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_timeout() - Handle timeout alarms...
+ * lpd_write() - Write a buffer of data to an LPD server.
+ * rresvport_af() - A simple implementation of rresvport_af().
+ * sigterm_handler() - Handle 'terminate' signals that stop the backend.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# include
+# include
+#endif /* WIN32 */
+
+
+/*
+ * Globals...
+ */
+
+static char tmpfilename[1024] = ""; /* Temporary spool file name */
+static int abort_job = 0; /* Non-zero if we get SIGTERM */
+
+
+/*
+ * The order for control and data files in LPD requests...
+ */
+
+#define ORDER_CONTROL_DATA 0 /* Control file first, then data */
+#define ORDER_DATA_CONTROL 1 /* Data file first, then control */
+
+
+/*
+ * What to reserve...
+ */
+
+#define RESERVE_NONE 0 /* Don't reserve a priviledged port */
+#define RESERVE_RFC1179 1 /* Reserve port 721-731 */
+#define RESERVE_ANY 2 /* Reserve port 1-1023 */
+
+
+/*
+ * Local functions...
+ */
+
+static int lpd_command(int lpd_fd, int timeout, char *format, ...);
+static int lpd_queue(const char *hostname, int port, const char *printer,
+ const char *filename,
+ const char *user, const char *title, int copies,
+ int banner, int format, int order, int reserve,
+ int manual_copies, int timeout);
+static void lpd_timeout(int sig);
+static int lpd_write(int lpd_fd, char *buffer, int length);
+#ifndef HAVE_RRESVPORT_AF
+static int rresvport_af(int *port, int family);
+#endif /* !HAVE_RRESVPORT_AF */
+static void sigterm_handler(int sig);
+
+
+/*
+ * '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 */
+ 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, /* File to print */
+ title[256]; /* Title string */
+ int port; /* Port number */
+ int status; /* Status of LPD job */
+ int banner; /* Print banner page? */
+ int format; /* Print format */
+ int order; /* Order of control/data files */
+ int reserve; /* Reserve priviledged port? */
+ int sanitize_title; /* Sanitize title string? */
+ int manual_copies, /* Do manual copies? */
+ timeout, /* Timeout */
+ copies; /* Number of copies */
+#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);
+
+ /*
+ * Ignore SIGPIPE and catch SIGTERM signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
+ argv[0]);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * 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(tmpfilename, sizeof(tmpfilename))) < 0)
+ {
+ perror("ERROR: unable to create temporary file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ 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(tmpfilename);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ close(fd);
+ filename = tmpfilename;
+ }
+ else
+ filename = argv[6];
+
+ /*
+ * Extract the hostname and printer name from the URI...
+ */
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if (!username[0])
+ {
+ /*
+ * If no username is in the device URI, then use the print job user...
+ */
+
+ strlcpy(username, argv[2], sizeof(username));
+ }
+
+ /*
+ * See if there are any options...
+ */
+
+ banner = 0;
+ format = 'l';
+ order = ORDER_CONTROL_DATA;
+ reserve = RESERVE_ANY;
+ manual_copies = 1;
+ timeout = 300;
+ sanitize_title = 1;
+
+#if defined(__APPLE__)
+ /* We want to pass utf-8 characters, not re-map them (3071945) */
+ sanitize_title= 0;
+#endif
+
+ 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 != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *options++;
+ *ptr = '\0';
+
+ if (*options == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ options ++;
+
+ for (ptr = value; *options && *options != '+' && *options != '&';)
+ if (ptr < (value + sizeof(value) - 1))
+ *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);
+ }
+ else if (strcasecmp(name, "reserve") == 0)
+ {
+ /*
+ * Set port reservation mode...
+ */
+
+ if (!value[0] ||
+ !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "true") ||
+ !strcasecmp(value, "rfc1179"))
+ reserve = RESERVE_RFC1179;
+ else if (!strcasecmp(value, "any"))
+ reserve = RESERVE_ANY;
+ else
+ reserve = RESERVE_NONE;
+ }
+ else if (strcasecmp(name, "manual_copies") == 0)
+ {
+ /*
+ * Set manual copies...
+ */
+
+ manual_copies = !value[0] ||
+ strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "true") == 0;
+ }
+ else if (strcasecmp(name, "sanitize_title") == 0)
+ {
+ /*
+ * Set sanitize title...
+ */
+
+ sanitize_title = !value[0] ||
+ strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "true") == 0;
+ }
+ else if (strcasecmp(name, "timeout") == 0)
+ {
+ /*
+ * Set the timeout...
+ */
+
+ if (atoi(value) > 0)
+ timeout = atoi(value);
+ }
+ }
+ }
+
+ /*
+ * Sanitize the document title...
+ */
+
+ strlcpy(title, argv[3], sizeof(title));
+
+ if (sanitize_title)
+ {
+ /*
+ * Sanitize the title string so that we don't cause problems on
+ * the remote end...
+ */
+
+ for (ptr = title; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
+ *ptr = '_';
+ }
+
+ /*
+ * Queue the job...
+ */
+
+ if (argc > 6)
+ {
+ if (manual_copies)
+ {
+ manual_copies = atoi(argv[4]);
+ copies = 1;
+ }
+ else
+ {
+ manual_copies = 1;
+ copies = atoi(argv[4]);
+ }
+
+ status = lpd_queue(hostname, port, resource + 1, filename,
+ username, title, copies,
+ banner, format, order, reserve, manual_copies, timeout);
+
+ if (!status)
+ fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
+ }
+ else
+ status = lpd_queue(hostname, port, resource + 1, filename,
+ username, title, 1,
+ banner, format, order, reserve, 1, timeout);
+
+ /*
+ * Remove the temporary file if necessary...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+ /*
+ * 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 */
+ int timeout, /* I - Seconds to wait for a response */
+ 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 */
+
+
+ /*
+ * Don't try to send commands if the job has been cancelled...
+ */
+
+ if (abort_job)
+ return (-1);
+
+ /*
+ * 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)
+ {
+ perror("ERROR: Unable to send LPD command");
+ return (-1);
+ }
+
+ /*
+ * Read back the status from the command and return it...
+ */
+
+ fprintf(stderr, "DEBUG: Reading command status...\n");
+
+ alarm(timeout);
+
+ if (recv(fd, &status, 1, 0) < 1)
+ {
+ fprintf(stderr, "WARNING: Remote host did not respond with command "
+ "status byte after %d seconds!\n", timeout);
+ status = errno;
+ }
+
+ alarm(0);
+
+ 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(const char *hostname, /* I - Host to connect to */
+ int port, /* I - Port to connect on */
+ const char *printer, /* I - Printer/queue name */
+ const char *filename, /* I - File to print */
+ const char *user, /* I - Requesting user */
+ const 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 */
+ int reserve, /* I - Reserve ports? */
+ int manual_copies, /* I - Do copies by hand... */
+ int timeout) /* I - Timeout... */
+{
+ FILE *fp; /* Job file */
+ char localhost[255]; /* Local host name */
+ int error; /* Error number */
+ struct stat filestats; /* File statistics */
+ int lport; /* LPD connection local port */
+ int fd; /* LPD socket */
+ char control[10240], /* LPD control 'file' */
+ *cptr; /* Pointer into control file string */
+ char status; /* Status byte from command */
+ char portname[255]; /* Port name */
+ http_addrlist_t *addrlist, /* Address list */
+ *addr; /* Socket address */
+ int copy; /* Copies written */
+ size_t nbytes; /* Number of bytes written */
+ off_t tbytes; /* Total bytes written */
+ char buffer[65536]; /* Output buffer */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Setup an alarm handler for timeouts...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGALRM, lpd_timeout);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = lpd_timeout;
+ sigaction(SIGALRM, &action, NULL);
+#else
+ signal(SIGALRM, lpd_timeout);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Find the printer...
+ */
+
+ sprintf(portname, "%d", port);
+
+ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n",
+ hostname);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Loop forever trying to print the file...
+ */
+
+ while (!abort_job)
+ {
+ /*
+ * First try to reserve a port for this connection...
+ */
+
+ fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
+ hostname, printer);
+
+ for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist;;
+ addr = addr->next)
+ {
+ /*
+ * Stop if this job has been cancelled...
+ */
+
+ if (abort_job)
+ {
+ httpAddrFreeList(addrlist);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Choose the next priviledged port...
+ */
+
+ if (!addr)
+ addr = addrlist;
+
+ lport --;
+
+ if (lport < 721 && reserve == RESERVE_RFC1179)
+ lport = 731;
+ else if (lport < 1)
+ lport = 1023;
+
+#ifdef HAVE_GETEUID
+ if (geteuid() || !reserve)
+#else
+ if (getuid() || !reserve)
+#endif /* HAVE_GETEUID */
+ {
+ /*
+ * Just create a regular socket...
+ */
+
+ if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
+ {
+ perror("ERROR: Unable to create socket");
+ sleep(1);
+
+ continue;
+ }
+
+ lport = 0;
+ }
+ else
+ {
+ /*
+ * We're running as root and want to comply with RFC 1179. Reserve a
+ * priviledged lport between 721 and 731...
+ */
+
+ if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
+ {
+ perror("ERROR: Unable to reserve port");
+ sleep(1);
+
+ continue;
+ }
+ }
+
+ /*
+ * Connect to the printer or server...
+ */
+
+ if (abort_job)
+ {
+ httpAddrFreeList(addrlist);
+
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
+ break;
+
+ error = errno;
+ close(fd);
+ fd = -1;
+
+ if (addr->next)
+ continue;
+
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n",
+ hostname);
+
+ httpAddrFreeList(addrlist);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (error == ECONNREFUSED || error == EHOSTDOWN ||
+ error == EHOSTUNREACH)
+ {
+ fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
+ hostname);
+ sleep(30);
+ }
+ else if (error == EADDRINUSE)
+ {
+ /*
+ * Try on another port...
+ */
+
+ sleep(1);
+ }
+ else
+ {
+ perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
+ sleep(30);
+ }
+ }
+
+ fprintf(stderr, "INFO: Connected to %s...\n", hostname);
+ fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
+ lport);
+
+ /*
+ * Next, open the print file and figure out its size...
+ */
+
+ if (stat(filename, &filestats))
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+
+ perror("ERROR: unable to stat print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ filestats.st_size *= manual_copies;
+
+ if ((fp = fopen(filename, "rb")) == NULL)
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+
+ perror("ERROR: unable to open print file for reading");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Send a job header to the printer, specifying no banner page and
+ * literal output...
+ */
+
+ if (lpd_command(fd, timeout, "\002%s\n",
+ printer)) /* Receive print job(s) */
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ httpGetHostname(localhost, sizeof(localhost));
+
+ snprintf(control, sizeof(control),
+ "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
+ "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
+ "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
+ localhost, user, title);
+ cptr = control + strlen(control);
+
+ if (banner)
+ {
+ snprintf(cptr, sizeof(control) - (cptr - control),
+ "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
+ "L%s\n",
+ localhost, user);
+ cptr += strlen(cptr);
+ }
+
+ while (copies > 0)
+ {
+ snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
+ format, (int)getpid() % 1000, localhost);
+ cptr += strlen(cptr);
+ copies --;
+ }
+
+ snprintf(cptr, sizeof(control) - (cptr - control),
+ "UdfA%03d%.15s\n"
+ "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
+ (int)getpid() % 1000, localhost, title);
+
+ fprintf(stderr, "DEBUG: Control file is:\n%s", control);
+
+ if (order == ORDER_CONTROL_DATA)
+ {
+ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ (int)getpid() % 1000, localhost))
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "INFO: Sending control file (%u bytes)\n",
+ (unsigned)strlen(control));
+
+ if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("ERROR: Unable to write control file");
+ }
+ else
+ {
+ alarm(timeout);
+
+ if (read(fd, &status, 1) < 1)
+ {
+ fprintf(stderr, "WARNING: Remote host did not respond with control "
+ "status byte after %d seconds!\n", timeout);
+ status = errno;
+ }
+
+ alarm(0);
+ }
+
+ 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...
+ */
+
+ if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
+ CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
+ localhost))
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "INFO: Sending data file (" CUPS_LLFMT " bytes)\n",
+ CUPS_LLCAST filestats.st_size);
+
+ tbytes = 0;
+ for (copy = 0; copy < manual_copies; copy ++)
+ {
+ rewind(fp);
+
+ while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+ {
+ fprintf(stderr, "INFO: Spooling LPR job, %.0f%% complete...\n",
+ 100.0 * 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)
+ {
+ perror("ERROR: Unable to send trailing nul to printer");
+ status = errno;
+ }
+ else
+ {
+ /*
+ * Read the status byte from the printer; if we can't read the byte
+ * back now, we should set status to "errno", however at this point
+ * we know the printer got the whole file and we don't necessarily
+ * want to requeue it over and over...
+ */
+
+ alarm(timeout);
+
+ if (recv(fd, &status, 1, 0) < 1)
+ {
+ fprintf(stderr, "WARNING: Remote host did not respond with data "
+ "status byte after %d seconds!\n", timeout);
+ status = 0;
+ }
+
+ alarm(0);
+ }
+
+ 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)
+ {
+ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ (int)getpid() % 1000, localhost))
+ {
+ httpAddrFreeList(addrlist);
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
+ (unsigned long)strlen(control));
+
+ if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("ERROR: Unable to write control file");
+ }
+ else
+ {
+ alarm(timeout);
+
+ if (read(fd, &status, 1) < 1)
+ {
+ fprintf(stderr, "WARNING: Remote host did not respond with control "
+ "status byte after %d seconds!\n", timeout);
+ status = errno;
+ }
+
+ alarm(0);
+ }
+
+ 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...
+ */
+
+ close(fd);
+ fclose(fp);
+
+ if (status == 0)
+ {
+ httpAddrFreeList(addrlist);
+
+ return (CUPS_BACKEND_OK);
+ }
+
+ /*
+ * Waiting for a retry...
+ */
+
+ sleep(30);
+ }
+
+ httpAddrFreeList(addrlist);
+
+ /*
+ * If we get here, then the job has been cancelled...
+ */
+
+ return (CUPS_BACKEND_FAILED);
+}
+
+
+/*
+ * 'lpd_timeout()' - Handle timeout alarms...
+ */
+
+static void
+lpd_timeout(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGALRM, lpd_timeout);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * '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 */
+
+
+ if (abort_job)
+ return (-1);
+
+ 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);
+}
+
+
+#ifndef HAVE_RRESVPORT_AF
+/*
+ * 'rresvport_af()' - A simple implementation of rresvport_af().
+ */
+
+static int /* O - Socket or -1 on error */
+rresvport_af(int *port, /* IO - Port number to bind to */
+ int family) /* I - Address family */
+{
+ http_addr_t addr; /* Socket address */
+ int fd; /* Socket file descriptor */
+
+
+ /*
+ * Try to create an IPv4 socket...
+ */
+
+ if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
+ return (-1);
+
+ /*
+ * Initialize the address buffer...
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.addr.sa_family = family;
+
+ /*
+ * Try to bind the socket to a reserved port...
+ */
+
+ while (*port > 511)
+ {
+ /*
+ * Set the port number...
+ */
+
+# ifdef AF_INET6
+ if (family == AF_INET6)
+ addr.ipv6.sin6_port = htons(*port);
+ else
+# endif /* AF_INET6 */
+ addr.ipv4.sin_port = htons(*port);
+
+ /*
+ * Try binding the port to the socket; return if all is OK...
+ */
+
+ if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
+ return (fd);
+
+ /*
+ * Stop if we have any error other than "address already in use"...
+ */
+
+ if (errno != EADDRINUSE)
+ {
+# ifdef WIN32
+ closesocket(fd);
+# else
+ close(fd);
+# endif /* WIN32 */
+
+ return (-1);
+ }
+
+ /*
+ * Try the next port...
+ */
+
+ (*port)--;
+ }
+
+ /*
+ * Wasn't able to bind to a reserved port, so close the socket and return
+ * -1...
+ */
+
+# ifdef WIN32
+ closesocket(fd);
+# else
+ close(fd);
+# endif /* WIN32 */
+
+ return (-1);
+}
+#endif /* !HAVE_RRESVPORT_AF */
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal */
+{
+ (void)sig; /* remove compiler warnings... */
+
+ abort_job = 1;
+}
+
+
+/*
+ * End of "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/parallel.c b/backend/parallel.c
new file mode 100644
index 000000000..d80f8e214
--- /dev/null
+++ b/backend/parallel.c
@@ -0,0 +1,731 @@
+/*
+ * "$Id: parallel.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * Parallel port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * 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
+#include
+#include
+#include "ieee1284.c"
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# include
+# include
+#endif /* WIN32 */
+
+#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) */
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int fd; /* Parallel device */
+ int rbytes; /* Number of bytes read */
+ 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 */
+ fd_set input, /* Input set for select() */
+ output; /* Output set for select() */
+ int paperout; /* Paper out? */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#ifdef __linux
+ unsigned int status; /* Port status (off-line, out-of-paper, etc.) */
+#endif /* __linux */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ list_devices();
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fputs("Usage: parallel job-id user title copies options [file]\n", stderr);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ fp = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: unable to open print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(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 (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fputs("INFO: Unable to open parallel port, queuing on next printer in class...\n",
+ stderr);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else if (errno == ENXIO || errno == EIO || errno == ENOENT)
+ {
+ fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open parallel port device file \"%s\": %s\n",
+ resource, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ 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);
+
+ /*
+ * Check printer status...
+ */
+
+ paperout = 0;
+
+#if defined(__linux) && defined(LP_POUTPA)
+ /*
+ * Show the printer status before we send the file...
+ */
+
+ while (!ioctl(fd, LPGETSTATUS, &status))
+ {
+ fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
+
+ if (status & LP_POUTPA)
+ {
+ fputs("WARNING: Media tray empty!\n", stderr);
+ fputs("STATUS: +media-tray-empty-error\n", stderr);
+
+ paperout = 1;
+ }
+
+ if (!(status & LP_PERRORP))
+ fputs("WARNING: Printer fault!\n", stderr);
+ else if (!(status & LP_PSELECD))
+ fputs("WARNING: Printer off-line.\n", stderr);
+ else
+ break;
+
+ sleep(5);
+ }
+#endif /* __linux && LP_POUTPA */
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#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...
+ */
+
+ wbytes = 0;
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (fp != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(fp, 0, SEEK_SET);
+ }
+
+ tbytes = 0;
+ while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ /*
+ * See if we are ready to read or write...
+ */
+
+ do
+ {
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+ FD_ZERO(&output);
+ FD_SET(fd, &output);
+ }
+ while (select(fd + 1, &input, &output, NULL, NULL) < 0);
+
+ if (FD_ISSET(fd, &input))
+ {
+ /*
+ * Read backchannel data...
+ */
+
+ if ((rbytes = read(fd, resource, sizeof(resource))) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(resource, rbytes, 1.0);
+ }
+ }
+
+ if (FD_ISSET(fd, &output))
+ {
+ /*
+ * Write print data...
+ */
+
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ /*
+ * Check for retryable errors...
+ */
+
+ if (errno == ENOSPC)
+ {
+ paperout = 1;
+ fputs("ERROR: Out of paper!\n", stderr);
+ fputs("STATUS: +media-tray-empty-error\n", stderr);
+ }
+ else if (errno != EAGAIN && errno != EINTR)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Update count and pointer...
+ */
+
+ if (paperout)
+ {
+ fputs("STATUS: -media-tray-empty-error\n", stderr);
+ paperout = 0;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+ }
+ }
+
+ if (wbytes < 0)
+ break;
+
+ if (argc > 6)
+ fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
+ (unsigned long)tbytes);
+ }
+ }
+
+ /*
+ * Close the socket connection and input file and return...
+ */
+
+ close(fd);
+ if (fp != 0)
+ close(fp);
+
+ return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+}
+
+
+/*
+ * '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 */
+ basedevice[255], /* Base device filename for ports */
+ device_id[1024], /* Device ID string */
+ make_model[1024]; /* Make and model */
+
+
+ if (!access("/dev/parallel/", 0))
+ strcpy(basedevice, "/dev/parallel/");
+ else if (!access("/dev/printers/", 0))
+ strcpy(basedevice, "/dev/printers/");
+ else if (!access("/dev/par0", 0))
+ strcpy(basedevice, "/dev/par");
+ else
+ strcpy(basedevice, "/dev/lp");
+
+ for (i = 0; i < 4; i ++)
+ {
+ /*
+ * Open the port, if available...
+ */
+
+ sprintf(device, "%s%d", basedevice, i);
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
+ fd = open(device, O_WRONLY);
+
+ if (fd >= 0)
+ {
+ /*
+ * Now grab the IEEE 1284 device ID string...
+ */
+
+ if (!get_device_id(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ NULL, NULL, 0))
+ printf("direct parallel:%s \"%s\" \"%s LPT #%d\" \"%s\"\n", device,
+ make_model, make_model, i + 1, device_id);
+ else
+ printf("direct parallel:%s \"Unknown\" \"LPT #%d\"\n", device, i + 1);
+
+ close(fd);
+ }
+ }
+#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 (interrupt-driven)\"\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 (polled)\"\n", device, i + 1);
+ }
+ }
+#elif defined(_AIX)
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 8; 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);
+ }
+ }
+#endif
+}
+
+
+/*
+ * End of "$Id: parallel.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/scsi-irix.c b/backend/scsi-irix.c
new file mode 100644
index 000000000..097071c23
--- /dev/null
+++ b/backend/scsi-irix.c
@@ -0,0 +1,231 @@
+/*
+ * "$Id: scsi-irix.c 4703 2005-09-26 19:33:58Z mike $"
+ *
+ * IRIX SCSI printer support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2003-2005 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contents:
+ *
+ * list_devices() - List the available SCSI printer devices.
+ * print_device() - Print a file to a SCSI device.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include /* memcpy() and friends */
+#include /* SCSI interface stuff */
+
+
+/*
+ * 'list_devices()' - List the available SCSI printer devices.
+ */
+
+void
+list_devices(void)
+{
+ puts("direct scsi \"Unknown\" \"SCSI Printer\"");
+}
+
+
+/*
+ * 'print_device()' - Print a file to a SCSI device.
+ */
+
+int /* O - Print status */
+print_device(const char *resource, /* I - SCSI device */
+ int fd, /* I - File to print */
+ int copies) /* I - Number of copies to print */
+{
+ int scsi_fd; /* SCSI file descriptor */
+ char buffer[8192]; /* Data buffer */
+ int bytes; /* Number of bytes */
+ int try; /* Current try */
+ dsreq_t scsi_req; /* SCSI request */
+ char scsi_cmd[6]; /* SCSI command data */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure we have a valid resource name...
+ */
+
+ if (strncmp(resource, "/dev/scsi/", 10) != 0)
+ {
+ fprintf(stderr, "ERROR: Bad SCSI device file \"%s\"!\n", resource);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Open the SCSI device file...
+ */
+
+ do
+ {
+ if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fputs("INFO: Unable to open SCSI device, queuing on next printer in class...\n",
+ stderr);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (1);
+ }
+
+ if (errno != EAGAIN && errno != EBUSY)
+ {
+ fprintf(stderr, "ERROR: Unable to open SCSI device \"%s\" - %s\n",
+ resource, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+ else
+ {
+ fprintf(stderr, "INFO: SCSI device \"%s\" busy; retrying...\n",
+ resource);
+ sleep(30);
+ }
+ }
+ }
+ while (scsi_fd == -1);
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (fd != 0)
+ {
+#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 */
+ }
+
+ /*
+ * Copy the print file to the device...
+ */
+
+ while (copies > 0)
+ {
+ if (fd != 0)
+ lseek(fd, 0, SEEK_SET);
+
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ {
+ memset(&scsi_req, 0, sizeof(scsi_req));
+
+ scsi_req.ds_flags = DSRQ_WRITE;
+ scsi_req.ds_time = 60 * 1000;
+ scsi_req.ds_cmdbuf = scsi_cmd;
+ scsi_req.ds_cmdlen = 6;
+ scsi_req.ds_databuf = buffer;
+ scsi_req.ds_datalen = bytes;
+
+ scsi_cmd[0] = 0x0a; /* Group 0 print command */
+ scsi_cmd[1] = 0x00;
+ scsi_cmd[2] = bytes / 65536;
+ scsi_cmd[3] = bytes / 256;
+ scsi_cmd[4] = bytes;
+ scsi_cmd[5] = 0x00;
+
+ for (try = 0; try < 10; try ++)
+ if (ioctl(scsi_fd, DS_ENTER, &scsi_req) < 0 ||
+ scsi_req.ds_status != 0)
+ {
+ fprintf(stderr, "WARNING: SCSI command timed out (%d); retrying...\n",
+ scsi_req.ds_status);
+ sleep(try + 1);
+ }
+ else
+ break;
+
+ if (try >= 10)
+ {
+ fprintf(stderr, "ERROR: Unable to send print data (%d)\n",
+ scsi_req.ds_status);
+ close(scsi_fd);
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ copies --;
+ }
+
+ /*
+ * Close the device and return...
+ */
+
+ close(fd);
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * End of "$Id: scsi-irix.c 4703 2005-09-26 19:33:58Z mike $".
+ */
diff --git a/backend/scsi-linux.c b/backend/scsi-linux.c
new file mode 100644
index 000000000..b5c1d1bef
--- /dev/null
+++ b/backend/scsi-linux.c
@@ -0,0 +1,249 @@
+/*
+ * "$Id: scsi-linux.c 4703 2005-09-26 19:33:58Z mike $"
+ *
+ * Linux SCSI printer support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2003-2005 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contents:
+ *
+ * list_devices() - List the available SCSI printer devices.
+ * print_device() - Print a file to a SCSI device.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+
+
+/*
+ * We currently only support the Linux 2.4 generic SCSI interface.
+ */
+
+#ifndef SG_DXFER_TO_DEV
+/*
+ * Dummy functions that do nothing on unsupported platforms...
+ */
+void list_devices(void) {}
+int print_device(const char *resource, int fd, int copies) { return (1); }
+#else
+
+
+/*
+ * 'list_devices()' - List the available SCSI printer devices.
+ */
+
+void
+list_devices(void)
+{
+ puts("direct scsi \"Unknown\" \"SCSI Printer\"");
+}
+
+
+/*
+ * 'print_device()' - Print a file to a SCSI device.
+ */
+
+int /* O - Print status */
+print_device(const char *resource, /* I - SCSI device */
+ int fd, /* I - File to print */
+ int copies) /* I - Number of copies to print */
+{
+ int scsi_fd; /* SCSI file descriptor */
+ char buffer[8192]; /* Data buffer */
+ int bytes; /* Number of bytes */
+ int try; /* Current try */
+ sg_io_hdr_t scsi_req; /* SCSI request */
+ unsigned char scsi_cmd[6], /* SCSI command data */
+ scsi_sense[32]; /* SCSI sense data */
+# if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+# endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure we have a valid resource name...
+ */
+
+ if (strncmp(resource, "/dev/sg", 7) != 0)
+ {
+ fprintf(stderr, "ERROR: Bad SCSI device file \"%s\"!\n", resource);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Open the SCSI device file...
+ */
+
+ do
+ {
+ if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fputs("INFO: Unable to open SCSI device, queuing on next printer in class...\n",
+ stderr);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno != EAGAIN && errno != EBUSY)
+ {
+ fprintf(stderr, "ERROR: Unable to open SCSI device \"%s\" - %s\n",
+ resource, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+ else
+ {
+ fprintf(stderr, "INFO: SCSI device \"%s\" busy; retrying...\n",
+ resource);
+ sleep(30);
+ }
+ }
+ }
+ while (scsi_fd == -1);
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (fd != 0)
+ {
+# 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 */
+ }
+
+ /*
+ * Copy the print file to the device...
+ */
+
+ while (copies > 0)
+ {
+ if (fd != 0)
+ lseek(fd, 0, SEEK_SET);
+
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ {
+ memset(&scsi_req, 0, sizeof(scsi_req));
+
+ scsi_req.interface_id = 'S';
+ scsi_req.dxfer_direction = SG_DXFER_TO_DEV;
+ scsi_req.cmd_len = 6;
+ scsi_req.mx_sb_len = sizeof(scsi_sense);
+ scsi_req.iovec_count = 0;
+ scsi_req.dxfer_len = bytes;
+ scsi_req.dxferp = buffer;
+ scsi_req.cmdp = scsi_cmd;
+ scsi_req.sbp = scsi_sense;
+ scsi_req.timeout = 60 * 1000;
+
+ scsi_cmd[0] = 0x0a; /* Group 0 print command */
+ scsi_cmd[1] = 0x00;
+ scsi_cmd[2] = bytes / 65536;
+ scsi_cmd[3] = bytes / 256;
+ scsi_cmd[4] = bytes;
+ scsi_cmd[5] = 0x00;
+
+ for (try = 0; try < 10; try ++)
+ if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 ||
+ scsi_req.status != 0)
+ {
+ fprintf(stderr, "WARNING: SCSI command timed out (%d); retrying...\n",
+ scsi_req.status);
+ sleep(try + 1);
+ }
+ else
+ break;
+
+ if (try >= 10)
+ {
+ fprintf(stderr, "ERROR: Unable to send print data (%d)\n",
+ scsi_req.status);
+ close(scsi_fd);
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ copies --;
+ }
+
+ /*
+ * Close the device and return...
+ */
+
+ close(fd);
+
+ return (CUPS_BACKEND_OK);
+}
+#endif /* !SG_DXFER_TO_DEV */
+
+
+/*
+ * End of "$Id: scsi-linux.c 4703 2005-09-26 19:33:58Z mike $".
+ */
diff --git a/backend/scsi.c b/backend/scsi.c
new file mode 100644
index 000000000..fdbc7f2f3
--- /dev/null
+++ b/backend/scsi.c
@@ -0,0 +1,223 @@
+/*
+ * "$Id: scsi.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * SCSI printer backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2003-2006 by Easy Software Products, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use
+ * of this software must display the following
+ * acknowledgement:
+ *
+ * This product includes software developed by Easy
+ * Software Products.
+ *
+ * 4. The name of Easy Software Products may not be used to
+ * endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contents:
+ *
+ * main() - Send a file to the specified SCSI printer.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# ifdef HAVE_SYS_IOCTL_H
+# include
+# endif /* HAVE_SYS_IOCTL_H */
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+void list_devices(void);
+int print_device(const char *resource, int fd, int copies);
+
+
+#ifdef __linux__
+# include "scsi-linux.c"
+#elif defined(__sgi)
+# include "scsi-irix.c"
+#else
+/*
+ * Dummy functions that do nothing on unsupported platforms...
+ */
+void list_devices(void) {}
+int print_device(const char *resource, int fd, int copies) { return (CUPS_BACKEND_FAILED); }
+#endif /* __linux */
+
+
+/*
+ * 'main()' - Send a file to the specified SCSI printer.
+ *
+ * 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) */
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int status; /* Exit status */
+#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);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ list_devices();
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fputs("Usage: scsi:/dev/file job-id user title copies options [file]\n", stderr);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ fp = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: unable to open print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(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';
+ }
+
+ /*
+ * Finally, send the print file...
+ */
+
+ status = print_device(resource, fp, copies);
+
+ /*
+ * Close input file and return...
+ */
+
+ if (fp != 0)
+ close(fp);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id: scsi.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/serial.c b/backend/serial.c
new file mode 100644
index 000000000..3079eef5e
--- /dev/null
+++ b/backend/serial.c
@@ -0,0 +1,1114 @@
+/*
+ * "$Id: serial.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * Serial port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * 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
+#include
+
+#ifdef __hpux
+# include
+#endif /* __hpux */
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# include
+# include
+# ifdef HAVE_SYS_IOCTL_H
+# include
+# endif /* HAVE_SYS_IOCTL_H */
+#endif /* WIN32 */
+
+#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 */
+
+#if defined(__APPLE__)
+# include
+# include
+# include
+# include
+#endif /* __APPLE__ */
+
+
+/*
+ * 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) */
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int fd; /* Parallel device */
+ int rbytes; /* Number of bytes read */
+ 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; /* Serial port options */
+ struct termios origopts; /* Original port options */
+ fd_set input, /* Input set for select() */
+ output; /* Output 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);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ list_devices();
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fputs("Usage: serial job-id user title copies options [file]\n", stderr);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ fp = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: unable to open print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(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 | O_NDELAY)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fputs("INFO: Unable to open serial port, queuing on next printer in class...\n",
+ stderr);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open serial port device file \"%s\": %s\n",
+ resource, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ while (fd < 0);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(fd, &origopts);
+ tcgetattr(fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+ opts.c_oflag &= ~OPOST; /* Don't post-process */
+
+ bufsize = 96; /* 9600 baud / 10 bits/char / 10Hz */
+ dtrdsr = 0; /* No dtr/dsr flow control */
+
+ if (options != NULL)
+ while (*options)
+ {
+ /*
+ * Get the name...
+ */
+
+ for (ptr = name; *options && *options != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *options++;
+ *ptr = '\0';
+
+ if (*options == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ options ++;
+
+ for (ptr = value; *options && *options != '+' && *options != '&';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *options++;
+ *ptr = '\0';
+
+ if (*options == '+')
+ options ++;
+ }
+ else
+ value[0] = '\0';
+
+ /*
+ * Process the option...
+ */
+
+ if (!strcasecmp(name, "baud"))
+ {
+ /*
+ * Set the baud rate...
+ */
+
+ bufsize = atoi(value) / 100;
+
+#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 */
+# ifdef B230400
+ case 230400 :
+ cfsetispeed(&opts, B230400);
+ cfsetospeed(&opts, B230400);
+ break;
+# endif /* B230400 */
+ default :
+ fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value);
+ break;
+ }
+#endif /* B19200 == 19200 */
+ }
+ else if (!strcasecmp(name, "bits"))
+ {
+ /*
+ * 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"))
+ {
+ /*
+ * Set parity checking...
+ */
+
+ if (!strcasecmp(value, "even"))
+ {
+ opts.c_cflag |= PARENB;
+ opts.c_cflag &= ~PARODD;
+ }
+ else if (!strcasecmp(value, "odd"))
+ {
+ opts.c_cflag |= PARENB;
+ opts.c_cflag |= PARODD;
+ }
+ else if (!strcasecmp(value, "none"))
+ opts.c_cflag &= ~PARENB;
+ else if (!strcasecmp(value, "space"))
+ {
+ /*
+ * Note: we only support space parity with 7 bits per character...
+ */
+
+ opts.c_cflag &= ~CSIZE;
+ opts.c_cflag |= CS8;
+ opts.c_cflag &= ~PARENB;
+ }
+ else if (!strcasecmp(value, "mark"))
+ {
+ /*
+ * Note: we only support mark parity with 7 bits per character
+ * and 1 stop bit...
+ */
+
+ opts.c_cflag &= ~CSIZE;
+ opts.c_cflag |= CS7;
+ opts.c_cflag &= ~PARENB;
+ opts.c_cflag |= CSTOPB;
+ }
+ }
+ else if (!strcasecmp(name, "flow"))
+ {
+ /*
+ * Set flow control...
+ */
+
+ if (!strcasecmp(value, "none"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (!strcasecmp(value, "soft"))
+ {
+ opts.c_iflag |= IXON | IXOFF;
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (!strcasecmp(value, "hard") ||
+ !strcasecmp(value, "rtscts"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag |= CRTSCTS;
+ }
+ else if (!strcasecmp(value, "dtrdsr"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag &= ~CRTSCTS;
+
+ dtrdsr = 1;
+ }
+ }
+ else if (!strcasecmp(name, "stop"))
+ {
+ switch (atoi(value))
+ {
+ case 1 :
+ opts.c_cflag &= ~CSTOPB;
+ break;
+
+ case 2 :
+ opts.c_cflag |= CSTOPB;
+ break;
+ }
+ }
+ }
+
+ tcsetattr(fd, TCSANOW, &opts);
+ fcntl(fd, F_SETFL, 0);
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#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);
+
+ wbytes = 0;
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (fp != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(fp, 0, SEEK_SET);
+ }
+
+ 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 = read(fp, buffer, bufsize)) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ /*
+ * See if we are ready to read or write...
+ */
+
+ do
+ {
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+ FD_ZERO(&output);
+ FD_SET(fd, &output);
+ }
+ while (select(fd + 1, &input, &output, NULL, NULL) < 0);
+
+ if (FD_ISSET(fd, &input))
+ {
+ /*
+ * Read backchannel data...
+ */
+
+ if ((rbytes = read(fd, resource, sizeof(resource))) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(resource, rbytes, 1.0);
+ }
+ }
+
+ if (FD_ISSET(fd, &output))
+ {
+ /*
+ * Write print data...
+ */
+
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ /*
+ * Check for retryable errors...
+ */
+
+ if (errno != EAGAIN && errno != EINTR)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Update count and pointer...
+ */
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+ }
+ }
+
+ if (wbytes < 0)
+ break;
+
+ if (argc > 6)
+ fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
+ (unsigned long)tbytes);
+ }
+ }
+
+ /*
+ * Close the serial port and input file and return...
+ */
+
+ tcsetattr(fd, TCSADRAIN, &origopts);
+
+ close(fd);
+ if (fp != 0)
+ close(fp);
+
+ return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+}
+
+
+/*
+ * '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__ */
+
+#if defined(__linux) || defined(linux) || defined(__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);
+# if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+# else
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+# endif /* _ARCH_PPC || powerpc || __powerpc */
+ }
+ }
+
+ for (i = 0; i < 16; i ++)
+ {
+ sprintf(device, "/dev/usb/ttyUSB%d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"USB 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);
+ }
+
+ 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);
+ }
+ }
+#elif defined(__APPLE__)
+ /*
+ * Standard serial ports on MacOS X...
+ */
+
+ kern_return_t kernResult;
+ mach_port_t masterPort;
+ io_iterator_t serialPortIterator;
+ CFMutableDictionaryRef classesToMatch;
+ io_object_t serialService;
+
+ printf("serial serial \"Unknown\" \"Serial Printer (serial)\"\n");
+
+ kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
+ if (KERN_SUCCESS != kernResult)
+ return;
+
+ /*
+ * Serial devices are instances of class IOSerialBSDClient.
+ */
+
+ classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
+ if (classesToMatch != NULL)
+ {
+ CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
+ CFSTR(kIOSerialBSDRS232Type));
+
+ kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
+ &serialPortIterator);
+ if (kernResult == KERN_SUCCESS)
+ {
+ while ((serialService = IOIteratorNext(serialPortIterator)))
+ {
+ CFTypeRef serialNameAsCFString;
+ CFTypeRef bsdPathAsCFString;
+ char serialName[128];
+ char bsdPath[1024];
+ Boolean result;
+
+
+ serialNameAsCFString =
+ IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOTTYDeviceKey),
+ kCFAllocatorDefault, 0);
+ if (serialNameAsCFString)
+ {
+ result = CFStringGetCString(serialNameAsCFString, serialName,
+ sizeof(serialName),
+ kCFStringEncodingASCII);
+ CFRelease(serialNameAsCFString);
+
+ if (result)
+ {
+ bsdPathAsCFString =
+ IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOCalloutDeviceKey),
+ kCFAllocatorDefault, 0);
+ if (bsdPathAsCFString)
+ {
+ result = CFStringGetCString(bsdPathAsCFString, bsdPath,
+ sizeof(bsdPath),
+ kCFStringEncodingASCII);
+ CFRelease(bsdPathAsCFString);
+
+ if (result)
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", bsdPath,
+ serialName);
+ }
+ }
+ }
+
+ IOObjectRelease(serialService);
+ }
+
+ IOObjectRelease(serialPortIterator); /* Release the iterator. */
+ }
+ }
+#endif
+}
+
+
+/*
+ * End of "$Id: serial.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/socket.c b/backend/socket.c
new file mode 100644
index 000000000..54b6a7796
--- /dev/null
+++ b/backend/socket.c
@@ -0,0 +1,418 @@
+/*
+ * "$Id: socket.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * AppSocket backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Send a file to the printer or server.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# include
+# include
+# include
+# include
+#endif /* WIN32 */
+
+
+/*
+ * '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) */
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int port; /* Port number */
+ char portname[255]; /* Port name */
+ int delay; /* Delay for retries... */
+ int fd; /* AppSocket */
+ int error; /* Error code (if any) */
+ http_addrlist_t *addrlist; /* Address list */
+ int rbytes; /* Number of bytes read */
+ int wbytes; /* Number of bytes written */
+ int nbytes; /* Number of bytes read */
+ size_t 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() */
+ output; /* Output 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);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\"");
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
+ argv[0]);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ fp = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: unable to open print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the hostname and port number from the URI...
+ */
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if (port == 0)
+ port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
+
+ /*
+ * Then try to connect to the remote host...
+ */
+
+ sprintf(portname, "%d", port);
+
+ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", hostname);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n",
+ hostname, port);
+
+ wbytes = 0;
+
+ while (copies > 0)
+ {
+ for (delay = 5;;)
+ {
+ if (!httpAddrConnect(addrlist, &fd))
+ {
+ error = errno;
+ fd = -1;
+
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fprintf(stderr, "INFO: Unable to connect to \"%s\", queuing on next printer in class...\n",
+ hostname);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (error == ECONNREFUSED || error == EHOSTDOWN ||
+ error == EHOSTUNREACH)
+ {
+ 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#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 != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(fp, 0, SEEK_SET);
+ }
+
+ fputs("INFO: Connected to host, sending print job...\n", stderr);
+
+ tbytes = 0;
+ while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ /*
+ * See if we are ready to read or write...
+ */
+
+ do
+ {
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+ FD_ZERO(&output);
+ FD_SET(fd, &output);
+ }
+ while (select(fd + 1, &input, &output, NULL, NULL) < 0);
+
+ if (FD_ISSET(fd, &input))
+ {
+ /*
+ * Read backchannel data...
+ */
+
+ if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(resource, rbytes, 1.0);
+ }
+ }
+
+ if (FD_ISSET(fd, &output))
+ {
+ /*
+ * Write print data...
+ */
+
+ if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0)
+ {
+ /*
+ * Check for retryable errors...
+ */
+
+ if (errno != EAGAIN && errno != EINTR)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Update count and pointer...
+ */
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+ }
+ }
+
+ if (wbytes < 0)
+ break;
+
+ if (argc > 6)
+ fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
+ (unsigned long)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 ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(resource, rbytes, 1.0);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ /*
+ * Close the socket connection...
+ */
+
+ close(fd);
+ }
+
+ httpAddrFreeList(addrlist);
+
+ /*
+ * Close the input file and return...
+ */
+
+ if (fp != 0)
+ close(fp);
+
+ if (wbytes >= 0)
+ fputs("INFO: Ready to print.\n", stderr);
+
+ return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+}
+
+
+/*
+ * End of "$Id: socket.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/backend/test1284.c b/backend/test1284.c
new file mode 100644
index 000000000..20a505d39
--- /dev/null
+++ b/backend/test1284.c
@@ -0,0 +1,95 @@
+/*
+ * "$Id: test1284.c 4903 2006-01-10 20:02:46Z mike $"
+ *
+ * IEEE-1284 support functions test program for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include
+#include
+#include
+#ifdef WIN32
+# include
+#else
+# include
+# include
+#endif /* WIN32 */
+#define DEBUG
+#include "ieee1284.c"
+
+
+/*
+ * 'main()' - Test the device-ID functions.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, /* Looping var */
+ fd; /* File descriptor */
+ char device_id[1024], /* 1284 device ID string */
+ make_model[1024], /* make-and-model string */
+ uri[1024]; /* URI string */
+
+
+ if (argc < 2)
+ {
+ puts("Usage: test1284 device-file [... device-file-N]");
+ exit(1);
+ }
+
+ for (i = 1; i < argc; i ++)
+ {
+ if ((fd = open(argv[i], O_RDWR)) < 0)
+ {
+ perror(argv[i]);
+ return (errno);
+ }
+
+ printf("%s:\n", argv[i]);
+
+ get_device_id(fd, device_id, sizeof(device_id), make_model,
+ sizeof(make_model), "test", uri, sizeof(uri));
+
+ printf(" device_id=\"%s\"\n", device_id);
+ printf(" make_model=\"%s\"\n", make_model);
+ printf(" uri=\"%s\"\n", uri);
+
+ close(fd);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: test1284.c 4903 2006-01-10 20:02:46Z mike $".
+ */
diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c
new file mode 100644
index 000000000..5c2ee4f4f
--- /dev/null
+++ b/backend/usb-darwin.c
@@ -0,0 +1,1899 @@
+/*
+ * "$Id: usb-darwin.c 4548 2005-06-27 02:33:50Z mike $"
+ *
+ * USB port on Darwin backend for the Common UNIX Printing System (CUPS).
+ *
+ * This file is included from "usb.c" when compiled on MacOS X or Darwin.
+ *
+ * Copyright 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * IMPORTANT: This Apple software is supplied to you by Apple Computer,
+ * Inc. ("Apple") in consideration of your agreement to the following
+ * terms, and your use, installation, modification or redistribution of
+ * this Apple software constitutes acceptance of these terms. If you do
+ * not agree with these terms, please do not use, install, modify or
+ * redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and
+ * subject to these terms, Apple grants you a personal, non-exclusive
+ * license, under Apple/s copyrights in this original Apple software (the
+ * "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ * Software, with or without modifications, in source and/or binary forms;
+ * provided that if you redistribute the Apple Software in its entirety and
+ * without modifications, you must retain this notice and the following
+ * text and disclaimers in all such redistributions of the Apple Software.
+ * Neither the name, trademarks, service marks or logos of Apple Computer,
+ * Inc. may be used to endorse or promote products derived from the Apple
+ * Software without specific prior written permission from Apple. Except
+ * as expressly stated in this notice, no other rights or licenses, express
+ * or implied, are granted by Apple herein, including but not limited to
+ * any patent rights that may be infringed by your derivative works or by
+ * other works in which the Apple Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis. APPLE
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contents:
+ *
+ * print_device() - Send a file to the specified USB port.
+ * list_devices() - List all USB devices.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include /* Used for writegReadMutex */
+
+#ifndef kPMPrinterURI
+# define kPMPrinterURI CFSTR("Printer URI")
+#endif
+
+/*
+ * Panther/10.3 kIOUSBInterfaceInterfaceID190
+ * Jaguar/10.2 kIOUSBInterfaceInterfaceID182
+ */
+
+#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
+#define kUSBLanguageEnglish 0x409
+
+/*
+ * Section 5.3 USB Printing Class spec
+ */
+
+#define kUSBPrintingSubclass 1
+#define kUSBPrintingProtocolNoOpen 0
+#define kUSBPrintingProtocolUnidirectional 1
+#define kUSBPrintingProtocolBidirectional 2
+
+#define kUSBPrintClassGetDeviceID 0
+#define kUSBPrintClassGetCentronicsStatus 1
+#define kUSBPrintClassSoftReset 2
+
+/*
+ * Apple MacOS X printer-class plugins
+ */
+
+#define kUSBPrinterClassTypeID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92))
+
+#define kUSBPrinterClassInterfaceID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92))
+
+#define kUSBGenericPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin")
+#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
+
+#define kUSBClassDriverProperty CFSTR("USB Printing Class")
+#define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/
+
+typedef union
+{
+ char b;
+ struct
+ {
+ unsigned reserved0 : 2;
+ unsigned paperError : 1;
+ unsigned select : 1;
+ unsigned notError : 1;
+ unsigned reserved1 : 3;
+ } status;
+} CentronicsStatusByte;
+
+typedef struct
+{
+ CFStringRef manufacturer; /* manufacturer name */
+ CFStringRef product; /* product name */
+ CFStringRef compatible; /* compatible product name */
+ CFStringRef serial; /* serial number */
+ CFStringRef command; /* command set */
+ CFStringRef ppdURL; /* url of the selected PPD, if any */
+} USBPrinterAddress;
+
+typedef IOUSBInterfaceInterface190 **USBPrinterInterface;
+
+typedef struct
+{
+ UInt8 requestType;
+ UInt8 request;
+ UInt16 value;
+ UInt16 index;
+ UInt16 length;
+ void *buffer;
+} USBIODeviceRequest;
+
+typedef struct classDriverContext
+{
+ IUNKNOWN_C_GUTS;
+ CFPlugInRef plugin; /* release plugin */
+ IUnknownVTbl **factory;
+ void *vendorReference;/* vendor class specific usage */
+ UInt32 location; /* unique location in bus topology */
+ UInt8 interfaceNumber;
+ UInt16 vendorID;
+ UInt16 productID;
+ USBPrinterInterface interface; /* identify the device to IOKit */
+ UInt8 outpipe; /* mandatory bulkOut pipe */
+ UInt8 inpipe; /* optional bulkIn pipe */
+ /*
+ ** general class requests
+ */
+ kern_return_t (*DeviceRequest)( struct classDriverContext **printer, USBIODeviceRequest *iorequest, UInt16 timeout );
+ kern_return_t (*GetString)( struct classDriverContext **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result );
+ /*
+ ** standard printer class requests
+ */
+ kern_return_t (*SoftReset)( struct classDriverContext **printer, UInt16 timeout );
+ kern_return_t (*GetCentronicsStatus)( struct classDriverContext **printer, CentronicsStatusByte *result, UInt16 timeout );
+ kern_return_t (*GetDeviceID)( struct classDriverContext **printer, CFStringRef *devid, UInt16 timeout );
+ /*
+ ** standard bulk device requests
+ */
+ kern_return_t (*ReadPipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count );
+ kern_return_t (*WritePipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count, Boolean eoj );
+ /*
+ ** interface requests
+ */
+ kern_return_t (*Open)( struct classDriverContext **printer, UInt32 location, UInt8 protocol );
+ kern_return_t (*Abort)( struct classDriverContext **printer );
+ kern_return_t (*Close)( struct classDriverContext **printer );
+ /*
+ ** initialize and terminate
+ */
+ kern_return_t (*Initialize)( struct classDriverContext **printer, struct classDriverContext **baseclass );
+ kern_return_t (*Terminate)( struct classDriverContext **printer );
+} USBPrinterClassContext;
+
+
+typedef struct usbPrinterClassType
+{
+ USBPrinterClassContext *classdriver;
+ CFUUIDRef factoryID;
+ UInt32 refCount;
+} USBPrinterClassType;
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Constants
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+/*
+ Debugging output to Console
+ DEBUG undefined or
+ DEBUG=0 production code: suppress console output
+
+ DEBUG=1 report errors (non-zero results)
+ DEBUG=2 report all results, generate dumps
+*/
+#if DEBUG==2
+#define DEBUG_ERR(c, x) showint(x, c)
+#define DEBUG_DUMP( text, buf, len ) dump( text, buf, len )
+#define DEBUG_CFString( text, a ) showcfstring( text, a )
+#define DEBUG_CFCompareString( text, a, b ) cmpcfs( text, a, b )
+#elif DEBUG==1
+#define DEBUG_ERR(c, x) if (c) fprintf(stderr, x, c)
+#define DEBUG_DUMP( text, buf, len )
+#define DEBUG_CFString( text, a )
+#define DEBUG_CFCompareString( text, a, b )
+#else
+#define DEBUG_ERR(c, x)
+#define DEBUG_DUMP( text, buf, len )
+#define DEBUG_CFString( text, a )
+#define DEBUG_CFCompareString( text, a, b )
+#endif
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Type Definitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+typedef struct
+{
+ /*
+ * Tagged/Tranparent Binary Communications Protocol
+ * TBCP read
+ */
+ Boolean tbcpQuoteReads; /* enable tbcp on reads */
+ Boolean escapeNextRead; /* last char of last read buffer was escape */
+ UInt8 *tbcpReadData; /* read buffer */
+ UInt32 readLength; /* read buffer length (all used) */
+ int match_endoffset, /* partial match of end TBCP sequence */
+ match_startoffset; /* partial match of start TBCP sequence */
+ /*
+ * TBCP write
+ */
+ UInt8 *tbcpWriteData; /* write buffer */
+ UInt32 tbcpBufferLength, /* write buffer allocated length */
+ tbcpBufferRemaining; /* write buffer not used */
+
+ Boolean sendStatusNextWrite;
+
+} PostScriptData;
+
+typedef struct
+{
+ CFPlugInRef plugin; /* valid until plugin is release */
+ USBPrinterClassContext **classdriver; /* usb printer class in user space */
+ CFStringRef bundle; /* class driver URI */
+ UInt32 location; /* unique location in USB topology */
+ USBPrinterAddress address; /* topology independent bus address */
+ CFURLRef reference; /* internal use */
+} USBPrinterInfo;
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+/*
+** IOKit to CF functions
+*/
+USBPrinterInfo *UsbCopyPrinter( USBPrinterInfo *aPrinter );
+CFMutableArrayRef UsbGetAllPrinters( void );
+void UsbReleasePrinter( USBPrinterInfo *aPrinter );
+void UsbReleaseAllPrinters( CFMutableArrayRef printers );
+kern_return_t UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result );
+kern_return_t UsbUnloadClassDriver( USBPrinterInfo *printer );
+kern_return_t UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle );
+CFStringRef UsbMakeFullUriAddress( USBPrinterInfo *aPrinter );
+
+int UsbSamePrinter( const USBPrinterAddress *lastTime, const USBPrinterAddress *thisTime );
+
+OSStatus UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout );
+
+
+/*******************************************************************************
+ Contains: Support IEEE-1284 DeviceID as a CFString.
+
+ Copyright 2000-2005 by Apple Computer, Inc., all rights reserved.
+
+ Description:
+ IEEE-1284 Device ID is referenced in USB and PPDT (1394.3). It allows
+ a computer peripheral to convey information about its required software
+ to the host system.
+
+ DeviceID is defined as a stream of ASCII bytes, commencing with one 16-bit
+ binary integer in Little-Endian format which describes how many bytes
+ of data are required by the entire DeviceID.
+
+ The stream of bytes is further characterized as a series of
+ key-value list pairs. In other words each key can be followed by one
+ or more values. Multiple key-value list pairs fill out the DeviceID stream.
+
+ Some keys are required: COMMAND SET (or CMD), MANUFACTURER (or MFG),
+ and MODEL (or MDL).
+
+ One needs to read the first two bytes of DeviceID to allocate storage
+ for the complete DeviceID string. Then a second read operation can
+ retrieve the entire string.
+
+ Often DeviceID is not very large. By allocating a reasonable buffer one
+ can fetch most device's DeviceID string on the first read.
+
+ A more formal definition of DeviceID.
+
+ = +
+
+ =
+ = :[,]*;
+
+ = +
+ = +
+
+ Some keys are defined in the standard. The standard specifies that
+ keys are case sensitive. White space is allowed in the key.
+
+ The standard does not say that values are case-sensitive.
+ Lexmark is known to ship printers with mixed-case value:
+ i.e., 'CLASS:Printer'
+
+ Required Keys:
+ 'COMMAND SET' or CMD
+ MANUFACTURER or MFG
+ MODEL or MDL
+
+ Optional Keys:
+ CLASS
+ Value PRINTER is referenced in the standard.
+
+ Observed Keys:
+ SN,SERN
+ Used by Hewlett-Packard for the serial number.
+
+
+*******************************************************************************/
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Pragmas
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Constants
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+#define kDeviceIDKeyCommand CFSTR("COMMAND SET:")
+#define kDeviceIDKeyCommandAbbrev CFSTR( "CMD:" )
+
+#define kDeviceIDKeyManufacturer CFSTR("MANUFACTURER:")
+#define kDeviceIDKeyManufacturerAbbrev CFSTR( "MFG:" )
+
+#define kDeviceIDKeyModel CFSTR("MODEL:")
+#define kDeviceIDKeyModelAbbrev CFSTR( "MDL:" )
+
+#define kDeviceIDKeySerial CFSTR("SN:")
+#define kDeviceIDKeySerialAbbrev CFSTR("SERN:")
+
+#define kDeviceIDKeyCompatible CFSTR("COMPATIBLITY ID:")
+#define kDeviceIDKeyCompatibleAbbrev CFSTR("CID:")
+
+/* delimiters */
+#define kDeviceIDKeyValuePairDelimiter CFSTR(";")
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Type definitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Function prototypes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+static CFStringRef CreateEncodedCFString(CFStringRef string);
+static CFRange DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options );
+static void parseOptions(const char *options, char *serial);
+
+CFStringRef
+DeviceIDCreateValueList( const CFStringRef deviceID,
+ const CFStringRef abbrevKey,
+ const CFStringRef key );
+
+static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax);
+static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax);
+
+/* Required to suppress redefinition warnings for these two symbols
+*/
+#if defined(TCP_NODELAY)
+#undef TCP_NODELAY
+#endif
+#if defined(TCP_MAXSEG)
+#undef TCP_MAXSEG
+#endif
+
+#include
+
+
+#define PRINTER_POLLING_INTERVAL 5 /* seconds */
+#define INITIAL_LOG_INTERVAL (PRINTER_POLLING_INTERVAL)
+#define SUBSEQUENT_LOG_INTERVAL (3*INITIAL_LOG_INTERVAL)
+
+/* WAITEOF_DELAY is number of seconds we'll wait for responses from the printer */
+/* after we've finished sending all the data */
+#define WAITEOF_DELAY 7
+
+#define USB_MAX_STR_SIZE 1024
+
+
+static volatile int done = 0;
+static int gWaitEOF = false;
+static pthread_cond_t *gReadCompleteConditionPtr = NULL;
+static pthread_mutex_t *gReadMutexPtr = NULL;
+
+
+
+#if DEBUG==2
+
+static char
+hexdigit( char c )
+{
+ return ( c < 0 || c > 15 )? '?': (c < 10)? c + '0': c - 10 + 'A';
+}
+
+static char
+asciidigit( char c )
+{
+ return (c< 20 || c > 0x7E)? '.': c;
+}
+
+void
+dump( char *text, void *s, int len )
+{
+ int i;
+ char *p = (char *) s;
+ char m[1+2*16+1+16+1];
+
+ fprintf( stderr, "%s pointer %x len %d\n", text, (unsigned int) p, len );
+
+ for ( ; len > 0; len -= 16 )
+ {
+ char *q = p;
+ char *out = m;
+ *out++ = '\t';
+ for ( i = 0; i < 16 && i < len; ++i, ++p )
+ {
+ *out++ = hexdigit( (*p >> 4) & 0x0F );
+ *out++ = hexdigit( *p & 0x0F );
+ }
+ for ( ;i < 16; ++i )
+ {
+ *out++ = ' ';
+ *out++ = ' ';
+ }
+ *out++ = '\t';
+ for ( i = 0; i < 16 && i < len; ++i, ++q )
+ *out++ = asciidigit( *q );
+ *out = 0;
+ m[ strlen( m ) ] = '\0';
+ fprintf( stderr, "%s\n", m );
+ }
+}
+
+void
+printcfs( char *text, CFStringRef s )
+{
+ char dest[1024];
+ if ( s != NULL )
+ {
+ if ( CFStringGetCString(s, dest, sizeof(dest), kCFStringEncodingUTF8) )
+ sprintf( dest, "%s <%s>\n", text, dest );
+ else
+ sprintf( dest, "%s [Unknown string]\n", text );
+ } else {
+ sprintf( dest, "%s [NULL]\n", text );
+ }
+ perror( dest );
+}
+
+void
+cmpcfs( char *text, CFStringRef a, CFStringRef b )
+{
+ CFRange found = {0, 0};
+
+ printcfs( text, a );
+ printcfs( " ", b );
+
+ if (a != NULL && b != NULL) {
+ found = CFStringFind( a, b, kCFCompareCaseInsensitive );
+
+ } else if (a == NULL && b == NULL) {
+ found.length = 1; /* Match */
+ found.location = 0;
+ } else {
+ found.length = 0; /* No match. */
+ }
+
+ if ( found.length > 0 )
+ fprintf( stderr, "matched @%d:%d\n", (int) found.location, (int) found.length);
+ else
+ fprintf( stderr, "not matched\n" );
+}
+#endif /*DEBUG==2 */
+
+#ifdef PARSE_PS_ERRORS
+static const char *nextLine (const char *buffer);
+static void parsePSError (char *sockBuffer, int len);
+
+
+static const char *nextLine (const char *buffer)
+{
+ const char *cptr, *lptr = NULL;
+ for (cptr = buffer; *cptr && lptr == NULL; cptr++)
+ if (*cptr == '\n' || *cptr == '\r')
+ lptr = cptr;
+ return lptr;
+}
+
+static void parsePSError (char *sockBuffer, int len)
+{
+ static char gErrorBuffer[1024] = "";
+ static char *gErrorBufferPtr = gErrorBuffer;
+ static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
+
+ char *pCommentBegin, *pCommentEnd, *pLineEnd;
+ char *logLevel;
+ char logstr[1024];
+ int logstrlen;
+
+ if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
+ gErrorBufferPtr = gErrorBuffer;
+ if (len > sizeof(gErrorBuffer) - 1)
+ len = sizeof(gErrorBuffer) - 1;
+
+ memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
+ gErrorBufferPtr += len;
+ *(gErrorBufferPtr + 1) = '\0';
+
+
+ pLineEnd = (char *)nextLine((const char *)gErrorBuffer);
+ while (pLineEnd != NULL)
+ {
+ *pLineEnd++ = '\0';
+
+ pCommentBegin = strstr(gErrorBuffer,"%%[");
+ pCommentEnd = strstr(gErrorBuffer, "]%%");
+ if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL)
+ {
+ pCommentEnd += 3; /* Skip past "]%%" */
+ *pCommentEnd = '\0'; /* There's always room for the nul */
+
+ if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
+ logLevel = "DEBUG";
+ else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
+ logLevel = "DEBUG";
+ else
+ logLevel = "INFO";
+
+ if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr))
+ {
+ /* If the string was trucnated make sure it has a linefeed before the nul */
+ logstrlen = sizeof(logstr) - 1;
+ logstr[logstrlen - 1] = '\n';
+ }
+ write(STDERR_FILENO, logstr, logstrlen);
+ }
+
+ /* move everything over... */
+ strcpy(gErrorBuffer, pLineEnd);
+ gErrorBufferPtr = gErrorBuffer;
+ pLineEnd = (char *)nextLine((const char *)gErrorBuffer);
+ }
+}
+#endif /* PARSE_PS_ERRORS */
+
+void *
+readthread( void *reference )
+{
+ /*
+ ** post a read to the device and write results to stdout
+ ** the final pending read will be Aborted in the main thread
+ */
+ UInt8 readbuffer[512];
+ UInt32 rbytes;
+ kern_return_t readstatus;
+ USBPrinterClassContext **classdriver = (USBPrinterClassContext **) reference;
+
+
+ do
+ {
+ rbytes = sizeof(readbuffer) - 1;
+ readstatus = (*classdriver)->ReadPipe( classdriver, readbuffer, &rbytes );
+ if ( kIOReturnSuccess == readstatus && rbytes > 0 )
+ {
+ write( STDOUT_FILENO, readbuffer, rbytes );
+ /* cntrl-d is echoed by the printer.
+ * NOTES:
+ * Xerox Phaser 6250D doesn't echo the cntrl-d.
+ * Xerox Phaser 6250D doesn't always send the product query.
+ */
+ if (gWaitEOF && readbuffer[rbytes-1] == 0x4)
+ break;
+#ifdef PARSE_PS_ERRORS
+ parsePSError(readbuffer, rbytes);
+#endif
+ }
+ } while ( gWaitEOF || !done ); /* Abort from main thread tests error here */
+
+ /* Let the other thread (main thread) know that we have
+ * completed the read thread...
+ */
+ pthread_mutex_lock(gReadMutexPtr);
+ pthread_cond_signal(gReadCompleteConditionPtr);
+ pthread_mutex_unlock(gReadMutexPtr);
+
+ return NULL;
+}
+
+/*
+* 'print_device()' - Send a file to the specified USB port.
+*/
+
+int print_device(const char *uri, const char *hostname, const char *resource, const char *options, int fd, int copies)
+{
+ UInt32 wbytes, /* Number of bytes written */
+ buffersize = 2048;
+ size_t nbytes; /* Number of bytes read */
+ off_t tbytes; /* Total number of bytes written */
+ char *buffer, /* Output buffer */
+ *bufptr; /* Pointer into buffer */
+
+ pthread_cond_t readCompleteCondition;
+ pthread_mutex_t readMutex;
+ pthread_t thr;
+ int thread_created = 0;
+
+ USBPrinterInfo *targetPrinter = NULL;
+ CFMutableArrayRef usbPrinters;
+ char manufacturer_buf[USB_MAX_STR_SIZE],
+ product_buf[USB_MAX_STR_SIZE],
+ serial_buf[USB_MAX_STR_SIZE];
+ CFStringRef manufacturer;
+ CFStringRef product;
+ CFStringRef serial;
+
+ OSStatus status = noErr;
+
+
+ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+ fprintf(stderr, "INFO: Opening the print file and connection...\n");
+
+ parseOptions(options, serial_buf);
+
+ if (resource[0] == '/')
+ resource++;
+
+ removePercentEscapes(hostname, manufacturer_buf, sizeof(manufacturer_buf));
+ removePercentEscapes(resource, product_buf, sizeof(product_buf));
+
+ manufacturer = CFStringCreateWithCString(NULL, manufacturer_buf, kCFStringEncodingUTF8);
+ product = CFStringCreateWithCString(NULL, product_buf, kCFStringEncodingUTF8);
+ serial = CFStringCreateWithCString(NULL, serial_buf, kCFStringEncodingUTF8);
+
+ USBPrinterInfo *activePrinter = NULL;
+ USBPrinterClassContext **classdriver;
+ int countdown = INITIAL_LOG_INTERVAL;
+ do
+ {
+ /* */
+ /* given a manufacturer and product, bind to a specific printer on the bus */
+ /* */
+ usbPrinters = UsbGetAllPrinters();
+ /* */
+ /* if we have at least one element of the URI, find a printer module that matches */
+ /* */
+ if ( NULL != usbPrinters && (manufacturer || product ) )
+ {
+ int i,
+ numPrinters = CFArrayGetCount(usbPrinters);
+ for ( i = 0; i < numPrinters; ++i )
+ {
+ int match = FALSE;
+ USBPrinterInfo *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbPrinters, i );
+ if ( printer )
+ {
+ match = printer->address.manufacturer && manufacturer? CFEqual(printer->address.manufacturer, manufacturer ): FALSE;
+ if ( match )
+ {
+ match = printer->address.product && product? CFEqual(printer->address.product, product ): FALSE;
+ }
+ if ( match && serial )
+ {
+ /* Note with old queues (pre Panther) the CUPS uri may have no serial number (serial==NULL). */
+ /* In this case, we will ignore serial number (as before), and we'll match to the first */
+ /* printer that agrees with manufacturer and product. */
+ /* If the CUPS uri does include a serial number, we'll enter this clause */
+ /* which requires the printer's serial number to match the CUPS serial number. */
+ /* The net effect is that for printers with a serial number, */
+ /* new queues must match the serial number, while old queues match any printer */
+ /* that satisfies the manufacturer/product match. */
+ /* */
+ match = printer->address.serial? CFEqual(printer->address.serial, serial ): FALSE;
+ }
+ if ( match )
+ {
+ targetPrinter = UsbCopyPrinter( printer );
+ break; /* for, compare partial address to address for each printer on usb bus */
+ }
+ }
+ }
+ }
+ UsbReleaseAllPrinters( usbPrinters );
+ if ( NULL != targetPrinter )
+ status = UsbRegistryOpen( &targetPrinter->address, &activePrinter );
+
+ if ( NULL == activePrinter )
+ {
+ sleep( PRINTER_POLLING_INTERVAL );
+ countdown -= PRINTER_POLLING_INTERVAL;
+ if ( !countdown )
+ {
+ /* periodically, write to the log so someone knows we're waiting */
+ if (NULL == targetPrinter)
+ fprintf( stderr, "WARNING: Printer not responding\n" );
+ else
+ fprintf( stderr, "INFO: Printer busy\n" );
+ countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 30 minutes */
+ }
+ }
+ } while ( NULL == activePrinter );
+
+ classdriver = activePrinter->classdriver;
+ if ( NULL == classdriver )
+ {
+ perror("ERROR: Unable to open USB Printing Class port");
+ return (status);
+ }
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (fd != 0)
+ {
+#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 */
+ }
+
+ buffer = malloc( buffersize );
+ if ( !buffer ) {
+ fprintf( stderr, "ERROR: Couldn't allocate internal buffer\n" );
+ status = -1;
+ }
+ else
+ {
+ fprintf(stderr, "INFO: Sending the print file...\n");
+ if (pthread_cond_init(&readCompleteCondition, NULL) == 0)
+ {
+ gReadCompleteConditionPtr = &readCompleteCondition;
+
+ if (pthread_mutex_init(&readMutex, NULL) == 0)
+ {
+ gReadMutexPtr = &readMutex;
+
+ if (pthread_create(&thr, NULL, readthread, classdriver ) > 0)
+ fprintf(stderr, "WARNING: Couldn't create read channel\n");
+ else
+ thread_created = 1;
+ }
+ }
+ }
+ /*
+ * the main thread sends the print file...
+ */
+ while (noErr == status && copies > 0)
+ {
+ copies --;
+ if (STDIN_FILENO != fd)
+ {
+ fputs("PAGE: 1 1", stderr);
+ lseek( fd, 0, SEEK_SET ); /* rewind */
+ }
+
+ tbytes = 0;
+ while (noErr == status && (nbytes = read(fd, buffer, buffersize)) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0 && noErr == status )
+ {
+ wbytes = nbytes;
+ status = (*classdriver)->WritePipe( classdriver, (UInt8*)bufptr, &wbytes, 0 /*nbytes > wbytes? 0: feof(fp)*/ );
+ if (wbytes < 0 || noErr != status)
+ {
+ OSStatus err;
+ err = (*classdriver)->Abort( classdriver );
+ fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled %ld)\n", status, err );
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+
+ if (fd != 0 && noErr == status)
+ fprintf(stderr, "INFO: Sending print file, %qd bytes...\n", (off_t)tbytes);
+ }
+ }
+ done = 1; /* stop scheduling reads */
+
+ if ( thread_created )
+ {
+ /* Give the read thread WAITEOF_DELAY seconds to complete all the data. If
+ * we are not signaled in that time then force the thread to exit by setting
+ * the waiteof to be false. Plese note that this relies on us using the timeout
+ * class driver.
+ */
+ struct timespec sleepUntil = { time(NULL) + WAITEOF_DELAY, 0 };
+ pthread_mutex_lock(&readMutex);
+ if (pthread_cond_timedwait(&readCompleteCondition, &readMutex, (const struct timespec *)&sleepUntil) != 0)
+ gWaitEOF = false;
+ pthread_mutex_unlock(&readMutex);
+ pthread_join( thr,NULL); /* wait for the child thread to return */
+ }
+
+ (*classdriver)->Close( classdriver ); /* forces the read to stop incase we are doing a blocking read */
+ UsbUnloadClassDriver( activePrinter );
+ /*
+ * Close the socket connection and input file and return...
+ */
+ free( buffer );
+
+ if (STDIN_FILENO != fd)
+ close(fd);
+
+ if (gReadCompleteConditionPtr != NULL)
+ pthread_cond_destroy(gReadCompleteConditionPtr);
+ if (gReadMutexPtr != NULL)
+ pthread_mutex_destroy(gReadMutexPtr);
+
+ return status == kIOReturnSuccess? 0: status;
+}
+
+static Boolean
+encodecfstr( CFStringRef cfsrc, char *dst, long len )
+{
+ return CFStringGetCString(cfsrc, dst, len, kCFStringEncodingUTF8 );
+}
+
+/*
+* 'list_devices()' - List all USB devices.
+*/
+void list_devices(void)
+{
+ char encodedManufacturer[1024];
+ char encodedProduct[1024];
+ char uri[1024];
+ CFMutableArrayRef usbBusPrinters = UsbGetAllPrinters();
+ CFIndex i, numPrinters = NULL != usbBusPrinters? CFArrayGetCount( usbBusPrinters ): 0;
+
+ puts("direct usb \"Unknown\" \"USB Printer (usb)\"");
+ for ( i = 0; i < numPrinters; ++i )
+ {
+ USBPrinterInfo *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbBusPrinters, i );
+
+ if ( printer )
+ {
+ CFStringRef addressRef = UsbMakeFullUriAddress( printer );
+ if ( addressRef )
+ {
+ if ( CFStringGetCString(addressRef, uri, sizeof(uri), kCFStringEncodingUTF8) ) {
+
+ encodecfstr( printer->address.manufacturer, encodedManufacturer, sizeof(encodedManufacturer) );
+ encodecfstr( printer->address.product, encodedProduct, sizeof(encodedProduct) );
+ printf("direct %s \"%s %s\" \"%s\"\n", uri, encodedManufacturer, encodedProduct, encodedProduct);
+ }
+ }
+ }
+ }
+ UsbReleaseAllPrinters( usbBusPrinters );
+ fflush(NULL);
+}
+
+
+static void parseOptions(const char *options, char *serial)
+{
+ char *serialnumber; /* ?serial= or ?location= */
+ char optionName[255], /* Name of option */
+ value[255], /* Value of option */
+ *ptr; /* Pointer into name or value */
+
+ if (serial)
+ *serial = '\0';
+
+ if (!options)
+ return;
+
+ serialnumber = NULL;
+
+ while (*options != '\0')
+ {
+ /*
+ * Get the name...
+ */
+ for (ptr = optionName; *options && *options != '=' && *options != '+' && *options != '&'; )
+ *ptr++ = *options++;
+
+ *ptr = '\0';
+ value[0] = '\0';
+
+ if (*options == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ options ++;
+
+ for (ptr = value; *options && *options != '+' && *options != '&';)
+ *ptr++ = *options++;
+
+ *ptr = '\0';
+
+ if (*options == '+' || *options == '&')
+ options ++;
+ }
+ else if (*options == '+' || *options == '&')
+ {
+ options ++;
+ }
+
+ /*
+ * Process the option...
+ */
+ if (strcasecmp(optionName, "waiteof") == 0)
+ {
+ if (strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "true") == 0)
+ {
+ gWaitEOF = true;
+ }
+ else if (strcasecmp(value, "off") == 0 ||
+ strcasecmp(value, "no") == 0 ||
+ strcasecmp(value, "false") == 0)
+ {
+ gWaitEOF = false;
+ }
+ else
+ {
+ fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
+ }
+ }
+ else if (strcasecmp(optionName, "serial") == 0 ||
+ strcasecmp(optionName, "location") == 0 )
+ {
+ strcpy(serial, value);
+ serialnumber = serial;
+ }
+ }
+
+ return;
+}
+
+
+/*!
+ * @function addPercentEscapes
+ * @abstract Encode a string with percent escapes
+ *
+ * @param src The source C string
+ * @param dst Desination buffer
+ * @param dstMax Size of desination buffer
+ *
+ * @result A non-zero return value for errors
+ */
+static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax)
+{
+ unsigned char c;
+ char *dstEnd = dst + dstMax - 1; /* -1 to leave room for the NUL */
+
+ while (*src)
+ {
+ c = *src++;
+
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || (c == '.' || c == '-' || c == '*' || c == '_'))
+ {
+ if (dst >= dstEnd)
+ return -1;
+
+ *dst++ = c;
+ }
+ else
+ {
+ if (dst >= dstEnd - 2)
+ return -1;
+
+ snprintf(dst, dstEnd - dst, "%%%02x", c);
+ dst += 3;
+ }
+ }
+
+ *dst = '\0';
+ return 0;
+}
+
+
+/*!
+ * @function removePercentEscapes
+ * @abstract Returns a string with any percent escape sequences replaced with their equivalent character
+ *
+ * @param src Source buffer
+ * @param srclen Number of bytes in source buffer
+ * @param dst Desination buffer
+ * @param dstMax Size of desination buffer
+ *
+ * @result A non-zero return value for errors
+ */
+static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax)
+{
+ int c;
+ const unsigned char *dstEnd = dst + dstMax;
+
+ while (*src && dst < dstEnd)
+ {
+ c = *src++;
+
+ if (c == '%')
+ {
+ sscanf(src, "%02x", &c);
+ src += 2;
+ }
+ *dst++ = (char)c;
+ }
+
+ if (dst >= dstEnd)
+ return -1;
+
+ *dst = '\0';
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------*
+
+ DelimitSubstring
+
+ Desc: Search a string from a starting location, looking for a given
+ delimiter. Return the range from the start of the search to the
+ delimiter, or end of string (whichever is shorter).
+
+ In: stringToSearch string which contains a substring that we search
+ delim string which marks the end of the string
+ bounds start and length of substring of stringToSearch
+ options case sensitive, anchored, etc.
+
+ Out: Range up to the delimiter.
+
+*-----------------------------------------------------------------------------*/
+static CFRange
+DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options )
+{
+ CFRange where_delim, /* where the delimiter was found */
+ value;
+ /* */
+ /* trim leading space by changing bounds */
+ /* */
+ while ( bounds.length > 0 && CFStringFindWithOptions( stringToSearch, CFSTR(" "), bounds, kCFCompareAnchored, &where_delim ) )
+ {
+ ++bounds.location; /* drop a leading ' ' */
+ --bounds.length;
+ }
+ value = bounds; /* assume match to the end of string, may be NULL */
+ /* */
+ /* find the delimiter in the remaining string */
+ /* */
+ if ( bounds.length > 0 && CFStringFindWithOptions( stringToSearch, delim, bounds, options, &where_delim ) )
+ {
+ /* */
+ /* match to the delimiter */
+ /* */
+ value.length = where_delim.location /* delim */ - bounds.location /* start of search */;
+ }
+ DEBUG_CFString( "\tFind target", stringToSearch );
+ DEBUG_CFString( "\tFind pattern", delim );
+ DEBUG_ERR( (int) value.location, "\t\tFound %d\n" );
+ DEBUG_ERR( (int) value.length, " length %d" );
+
+ return value;
+}
+
+
+/*-----------------------------------------------------------------------------*
+
+ DeviceIDCreateValueList
+
+ Desc: Create a new string for the value list of the specified key.
+ The key may be specified as two strings (an abbreviated form
+ and a standard form). NULL can be passed for either form of
+ the key.
+
+ (Although passing NULL for both forms of the key is considered
+ bad form[!] it is handled correctly.)
+
+ In: deviceID the device's IEEE-1284 DeviceID key-value list
+ abbrevKey the key we're interested in (NULL allowed)
+ key
+
+ Out: CFString the value list
+ or NULL key wasn't found in deviceID
+
+*-----------------------------------------------------------------------------*/
+CFStringRef
+DeviceIDCreateValueList( const CFStringRef deviceID, const CFStringRef abbrevKey, const CFStringRef key )
+{
+ CFRange found = CFRangeMake( -1,0); /* note CFStringFind sets length 0 if string not found */
+ CFStringRef valueList = NULL;
+
+ DEBUG_CFString( "---------DeviceIDCreateValueList DeviceID:", deviceID );
+ DEBUG_CFString( "---------DeviceIDCreateValueList key:", key );
+ DEBUG_CFString( "---------DeviceIDCreateValueList abbrevkey:", abbrevKey );
+ if ( NULL != deviceID && NULL != abbrevKey )
+ found = CFStringFind( deviceID, abbrevKey, kCFCompareCaseInsensitive );
+ if ( NULL != deviceID && NULL != key && found.length <= 0 )
+ found = CFStringFind( deviceID, key, kCFCompareCaseInsensitive );
+ if ( found.length > 0 )
+ {
+ /* the key is at found */
+ /* the value follows the key until we reach the semi-colon, or end of string */
+ /* */
+ CFRange search = CFRangeMake( found.location + found.length,
+ CFStringGetLength( deviceID ) - (found.location + found.length) );
+ /* */
+ /* finally extract the string */
+ /* */
+ valueList = CFStringCreateWithSubstring ( kCFAllocatorDefault, deviceID,
+ DelimitSubstring( deviceID, kDeviceIDKeyValuePairDelimiter, search, kCFCompareCaseInsensitive ) );
+ DEBUG_CFString( "---------DeviceIDCreateValueList:", valueList );
+ }
+ return valueList;
+
+}
+
+
+
+/******************************************************************************/
+
+/*-----------------------------------------------------------------------------*
+
+CompareSameString
+
+Desc: Return the CFCompare result for two strings, either or both of which
+ can be NULL.
+
+In:
+ a current value
+ b last value
+
+Out:
+ 0 if the strings match
+ non-zero if the strings don't match
+
+*-----------------------------------------------------------------------------*/
+static int
+CompareSameString( const CFStringRef a, const CFStringRef b )
+{
+ if ( NULL == a && NULL == b )
+ return 0;
+ else if ( NULL != a && NULL != b )
+ return CFStringCompare( a, b, kCFCompareAnchored );
+ else
+ return 1; /* one of a or b is NULL this time, but wasn't last time */
+}
+
+
+/******************************************************************************/
+kern_return_t
+UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle )
+{
+ kern_return_t kr = kUSBPrinterClassDeviceNotOpen;
+ if ( NULL != classDriverBundle )
+ printer->bundle = classDriverBundle; /* vendor-specific class override */
+ else
+#ifdef TIMEOUT
+ classDriverBundle = kUSBGenericTOPrinterClassDriver; /* supply the generic TIMEOUT class driver */
+#else
+ classDriverBundle = kUSBGenericPrinterClassDriver; /* supply the generic class driver */
+#endif
+ DEBUG_CFString( "UsbLoadClassDriver classDriverBundle", classDriverBundle );
+ if ( NULL != classDriverBundle )
+ {
+ USBPrinterClassContext **classdriver = NULL;
+ CFURLRef classDriverURL = CFURLCreateWithFileSystemPath( NULL, classDriverBundle, kCFURLPOSIXPathStyle, TRUE );
+ CFPlugInRef plugin = NULL == classDriverURL? NULL: CFPlugInCreate( NULL, classDriverURL );
+ if ( NULL != plugin)
+ {
+ /* See if this plug-in implements the Test type. */
+ CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn( kUSBPrinterClassTypeID, plugin );
+
+ /* If there are factories for the requested type, attempt to */
+ /* get the IUnknown interface. */
+ DEBUG_ERR( 0, "UsbLoadClassDriver plugin %x\n" );
+ if (NULL != factories && CFArrayGetCount(factories) > 0)
+ {
+ /* Get the factory ID for the first location in the array of IDs. */
+ CFUUIDRef factoryID = CFArrayGetValueAtIndex( factories, 0 );
+ /* Use the factory ID to get an IUnknown interface. */
+ /* Here the code for the PlugIn is loaded. */
+ IUnknownVTbl **iunknown = CFPlugInInstanceCreate( NULL, factoryID, kUSBPrinterClassTypeID );
+ /* If this is an IUnknown interface, query for the Test interface. */
+ DEBUG_ERR( 0, "UsbLoadClassDriver factories %x\n" );
+ if (NULL != iunknown)
+ {
+ DEBUG_ERR( 0, "UsbLoadClassDriver CFPlugInInstanceCreate %x\n" );
+ kr = (*iunknown)->QueryInterface( iunknown, CFUUIDGetUUIDBytes(interfaceID), (LPVOID *) &classdriver );
+
+ (*iunknown)->Release( iunknown );
+ if ( S_OK == kr && NULL != classdriver )
+ {
+ DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface %x\n" );
+ printer->plugin = plugin;
+ kr = (*classdriver)->Initialize( classdriver, printer->classdriver );
+
+ kr = kIOReturnSuccess;
+ printer->classdriver = classdriver;
+ }
+ else
+ {
+ DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface FAILED %x\n" );
+ }
+ }
+ else
+ {
+ DEBUG_ERR( kr, "UsbLoadClassDriver CFPlugInInstanceCreate FAILED %x\n" );
+ }
+ }
+ else
+ {
+ DEBUG_ERR( kr, "UsbLoadClassDriver factories FAILED %x\n" );
+ }
+ }
+ else
+ {
+ DEBUG_ERR( kr, "UsbLoadClassDriver plugin FAILED %x\n" );
+ }
+ if ( kr != kIOReturnSuccess || NULL == plugin || NULL == classdriver )
+ {
+ UsbUnloadClassDriver( printer );
+ }
+ }
+
+ return kr;
+}
+
+
+kern_return_t
+UsbUnloadClassDriver( USBPrinterInfo *printer )
+{
+ DEBUG_ERR( kIOReturnSuccess, "UsbUnloadClassDriver %x\n" );
+ if ( NULL != printer->classdriver )
+ (*printer->classdriver)->Release( printer->classdriver );
+ printer->classdriver = NULL;
+
+ if ( NULL != printer->plugin )
+ CFRelease( printer->plugin );
+ printer->plugin = NULL;
+
+ return kIOReturnSuccess;
+}
+
+
+/*-----------------------------------------------------------------------------*
+
+ UsbAddressDispose
+
+ Desc: deallocates anything used to create a persistent printer address
+
+ In: address the printer address we've created
+
+ Out:
+
+*-----------------------------------------------------------------------------*/
+void
+UsbAddressDispose( USBPrinterAddress *address )
+{
+ if ( address->product != NULL ) CFRelease( address->product );
+ if ( address->manufacturer != NULL ) CFRelease( address->manufacturer );
+ if ( address->serial != NULL ) CFRelease( address->serial );
+ if ( address->command != NULL ) CFRelease( address->command );
+
+ address->product =
+ address->manufacturer =
+ address->serial =
+ address->command = NULL;
+
+}
+
+/*-----------------------------------------------------------------------------*
+
+ UsbGetPrinterAddress
+
+ Desc: Given a printer we're enumerating, discover it's persistent
+ reference.
+
+ A "persistent reference" is one which enables us to identify
+ a printer regardless of where it resides on the USB topology,
+ and enumeration sequence.
+
+ To do this, we actually construct a reference from information
+ buried inside the printer. First we look at the USB device
+ descripton: an ideally defined device will support strings for
+ manufacturer and product id, and serial number. The serial number
+ will be unique for each printer.
+
+ Our prefered identification fetches the IEEE-1284 device id string.
+ This transparently handled IEEE-1284 compatible printers which
+ connected over a USB-parallel cable. Only if we can't get all the
+ information to uniquely identify the printer do we try the strings
+ referenced in the printer's USB device descriptor. (These strings
+ are typically absent in a USB-parallel cable.)
+
+ If a device doesn't support serial numbers we have a problem:
+ we can't distinguish between two identical printers. Unique serial
+ numbers allow us to distinguish between two same-model, same-manufacturer
+ USB printers.
+
+ In:
+ thePrinter iterator required for fetching device descriptor
+ devRefNum required to configure the interface
+
+ Out:
+ address->manufacturer
+ address->product
+ address->serial
+ Any (and all) of these may be NULL if we can't retrieve
+ information for IEEE1284 DeviceID or the USB device
+ descriptor. Caller should be prepared to handle such a case.
+ address->command
+ May be updated.
+
+*-----------------------------------------------------------------------------*/
+OSStatus
+UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout )
+{
+
+ /* */
+ /* start by assuming the device is not IEEE-1284 compliant */
+ /* and that we can't read in the required strings. */
+ /* */
+ OSStatus err;
+ CFStringRef deviceId = NULL;
+ USBPrinterClassContext **printer = NULL == thePrinter? NULL: thePrinter->classdriver;
+
+ address->manufacturer =
+ address->product =
+ address->compatible =
+ address->serial =
+ address->command = NULL;
+
+ DEBUG_DUMP( "UsbGetPrinterAddress thePrinter", thePrinter, sizeof(USBPrinterInfo) );
+
+ err = (*printer)->GetDeviceID( printer, &deviceId, timeout );
+ if ( noErr == err && NULL != deviceId )
+ {
+ /* the strings embedded here are defined in the IEEE1284 spec */
+ /* */
+ /* use the MFG/MANUFACTURER for the manufacturer */
+ /* and the MDL/MODEL for the product */
+ /* there is no serial number defined in IEEE1284 */
+ /* but it's been observed in recent HP printers */
+ /* */
+ address->command = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCommandAbbrev, kDeviceIDKeyCommand );
+
+ address->product = DeviceIDCreateValueList( deviceId, kDeviceIDKeyModelAbbrev, kDeviceIDKeyModel );
+ address->compatible = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCompatibleAbbrev, kDeviceIDKeyCompatible );
+
+ address->manufacturer = DeviceIDCreateValueList( deviceId, kDeviceIDKeyManufacturerAbbrev, kDeviceIDKeyManufacturer );
+
+ address->serial = DeviceIDCreateValueList( deviceId, kDeviceIDKeySerialAbbrev, kDeviceIDKeySerial );
+ CFRelease( deviceId );
+ }
+ DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->product", address->product );
+ DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->compatible", address->compatible );
+ DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->manufacturer", address->manufacturer );
+ DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->serial", address->serial );
+
+ if ( NULL == address->product || NULL == address->manufacturer || NULL == address->serial )
+ {
+ /* */
+ /* if the manufacturer or the product or serial number were not specified in DeviceID */
+ /* try to construct the address using USB English string descriptors */
+ /* */
+ IOUSBDeviceDescriptor desc;
+ USBIODeviceRequest request;
+
+ request.requestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBDevice );
+ request.request = kUSBRqGetDescriptor;
+ request.value = (kUSBDeviceDesc << 8) | 0;
+ request.index = 0; /* not kUSBLanguageEnglish*/
+ request.length = sizeof(desc);
+ request.buffer = &desc;
+ err = (*printer)->DeviceRequest( printer, &request, timeout );
+ DEBUG_ERR( (kern_return_t) err, "UsbGetPrinterAddress: GetDescriptor %x" );
+ if ( kIOReturnSuccess == err )
+ {
+ /* once we've retrieved the device descriptor */
+ /* try to fill in missing pieces of information */
+ /* */
+ /* Don't override any information already retrieved from DeviceID. */
+
+ if ( NULL == address->product)
+ {
+ err = (*printer)->GetString( printer, desc.iProduct, kUSBLanguageEnglish, timeout, &address->product );
+ if ( kIOReturnSuccess != err || address->product == NULL) {
+ address->product = CFSTR("Unknown");
+ }
+ }
+ DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->product\n", address->product );
+
+ if ( NULL == address->manufacturer )
+ {
+ err = (*printer)->GetString( printer, desc.iManufacturer, kUSBLanguageEnglish, timeout, &address->manufacturer );
+ if (kIOReturnSuccess != err || address->manufacturer == NULL) {
+ address->manufacturer = CFSTR("Unknown");
+ }
+ }
+ DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->manufacturer\n", address->manufacturer );
+
+ if ( NULL == address->serial )
+ {
+ /* if the printer doesn't have a serial number, use locationId */
+ if ( 0 == desc.iSerialNumber )
+ {
+ address->serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), (*printer)->location );
+ }
+ else
+ {
+ err = (*printer)->GetString( printer, desc.iSerialNumber, kUSBLanguageEnglish, timeout, &address->serial );
+ /* trailing NULs aren't handled correctly in URI */
+ if ( address->serial )
+ {
+ UniChar nulbyte = { 0 };
+ CFStringRef trim = CFStringCreateWithCharacters(NULL, &nulbyte, 1);
+ CFMutableStringRef newserial = CFStringCreateMutableCopy(NULL, 0, address->serial);
+
+ CFStringTrim( newserial, trim );
+
+ CFRelease(trim);
+ CFRelease( address->serial );
+
+ address->serial = newserial;
+ }
+ }
+ }
+ DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->serial\n", address->serial );
+ }
+ }
+ if ( NULL != address->product)
+ CFRetain(address->product); /* UsbGetString is really a UsbCopyString. */
+ if ( NULL != address->manufacturer )
+ CFRetain( address->manufacturer );
+ if ( NULL != address->serial )
+ CFRetain( address->serial );
+ return err;
+}
+
+
+/*-----------------------------------------------------------------------------*
+
+UsbSamePrinter
+
+ Desc: match two Usb printer address; return TRUE if they are the same.
+
+ In: a the persistent address found last time
+ b the persistent address found this time
+
+ Out: non-zero iff the addresses are the same
+
+*-----------------------------------------------------------------------------*/
+int
+UsbSamePrinter( const USBPrinterAddress *a, const USBPrinterAddress *b )
+{
+ int result = 0;
+ DEBUG_CFCompareString( "UsbSamePrinter serial", a->serial, b->serial );
+ DEBUG_CFCompareString( "UsbSamePrinter product", a->product, b->product );
+ DEBUG_CFCompareString( "UsbSamePrinter manufacturer", a->manufacturer, b->manufacturer );
+
+ result = !CompareSameString( a->serial, b->serial );
+ if ( result ) result = !CompareSameString( a->product, b->product );
+ if ( result ) result = !CompareSameString( a->manufacturer, b->manufacturer );
+
+ return result;
+}
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Method: UsbMakeFullUriAddress
+
+ Input Parameters:
+
+ Output Parameters:
+
+ Description:
+ Fill in missing address information
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CFStringRef
+UsbMakeFullUriAddress( USBPrinterInfo *printer )
+{
+ /* */
+ /* fill in missing address information. */
+ /* */
+ CFMutableStringRef printerUri = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("usb://") );
+ if ( NULL != printerUri )
+ {
+ CFStringRef serial = printer->address.serial;
+
+ CFStringAppend(printerUri, printer->address.manufacturer? CreateEncodedCFString( printer->address.manufacturer ): CFSTR("Unknown") );
+ CFStringAppend(printerUri, CFSTR("/") );
+
+ CFStringAppend(printerUri, printer->address.product? CreateEncodedCFString( printer->address.product ): CFSTR("Unknown") );
+
+ /*Handle the common case where there is no serial number (S450?) */
+ CFStringAppend(printerUri, serial == NULL? CFSTR("?location="): CFSTR("?serial=") );
+ if ( serial == NULL)
+ serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), printer->location );
+
+ CFStringAppend(printerUri, serial? CreateEncodedCFString( serial ): CFSTR("Unknown") );
+ }
+
+ return printerUri;
+}
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Method: UsbGetAllPrinters
+
+ Input Parameters:
+
+ Output Parameters:
+ array of all USB printers on the system
+
+ Description:
+ Build a list of USB printers by iterating IOKit USB objects
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+CFMutableArrayRef
+UsbGetAllPrinters( void )
+{
+ kern_return_t kr; /* kernel errors */
+ mach_port_t master_device_port = 0;
+ io_service_t usbInterface = 0;
+ io_iterator_t iter = 0;
+ CFMutableArrayRef printers = CFArrayCreateMutable( NULL, 0, NULL ); /* all printers */
+
+ do
+ {
+
+ kr = IOMasterPort( bootstrap_port, &master_device_port );
+ DEBUG_ERR( kr, "UsbGetAllPrinters IOMasterPort %x\n" );
+ if(kIOReturnSuccess != kr) break;
+
+ {
+ CFDictionaryRef usbMatch = NULL;
+
+ /* iterate over all interfaces. */
+ usbMatch = IOServiceMatching(kIOUSBInterfaceClassName);
+ if ( !usbMatch ) break;
+ DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceMatching %x\n" );
+
+ /* IOServiceGetMatchingServices() consumes the usbMatch reference so we don't need to release it. */
+ kr = IOServiceGetMatchingServices(master_device_port, usbMatch, &iter);
+ usbMatch = NULL;
+
+ DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceGetMatchingServices %x\n" );
+ if(kIOReturnSuccess != kr || iter == NULL) break;
+ }
+
+ while ( NULL != (usbInterface = IOIteratorNext(iter)) )
+ {
+ IOCFPlugInInterface **iodev;
+ USBPrinterInterface intf;
+ HRESULT res;
+ SInt32 score;
+ CFMutableDictionaryRef properties;
+ CFStringRef classDriver = NULL;
+
+ kr = IORegistryEntryCreateCFProperties( usbInterface, &properties, kCFAllocatorDefault, kNilOptions);
+ if ( kIOReturnSuccess == kr && NULL != properties)
+ {
+ classDriver = (CFStringRef) CFDictionaryGetValue( properties, kUSBClassDriverProperty );
+ if ( NULL != classDriver )
+ CFRetain( classDriver );
+ CFRelease( properties );
+ }
+
+ kr = IOCreatePlugInInterfaceForService( usbInterface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &iodev,
+ &score);
+
+ DEBUG_ERR( kr, "UsbGetAllPrinters IOCreatePlugInInterfaceForService %x\n" );
+ if ( kIOReturnSuccess == kr )
+ {
+ UInt8 intfClass = 0;
+ UInt8 intfSubClass = 0;
+
+ res = (*iodev)->QueryInterface( iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
+ DEBUG_ERR( (kern_return_t) res, "UsbGetAllPrinters QueryInterface %x\n" );
+
+ (*iodev)->Release(iodev);
+ if ( noErr != res ) break;
+
+ kr = (*intf)->GetInterfaceClass(intf, &intfClass);
+ DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceClass %x\n");
+ if ( kIOReturnSuccess == kr )
+ kr = (*intf)->GetInterfaceSubClass(intf, &intfSubClass);
+ DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceSubClass %x\n");
+
+ if ( kIOReturnSuccess == kr &&
+ kUSBPrintingClass == intfClass &&
+ kUSBPrintingSubclass == intfSubClass )
+ {
+
+ USBPrinterInfo printer,
+ *printerInfo;
+ /*
+ For each type of printer specified in the lookup spec array, find
+ all of that type of printer and add the results to the list of found
+ printers.
+ */
+ /* create this printer's persistent address */
+ memset( &printer, 0, sizeof(USBPrinterInfo) );
+ kr = (*intf)->GetLocationID(intf, &printer.location);
+ DEBUG_ERR(kr, "UsbGetAllPrinters GetLocationID %x\n");
+ if ( kIOReturnSuccess == kr )
+ {
+ kr = UsbLoadClassDriver( &printer, kUSBPrinterClassInterfaceID, classDriver );
+ DEBUG_ERR(kr, "UsbGetAllPrinters UsbLoadClassDriver %x\n");
+ if ( kIOReturnSuccess == kr && printer.classdriver )
+ {
+ (*(printer.classdriver))->interface = intf;
+ kr = UsbGetPrinterAddress( &printer, &printer.address, 60000L );
+ {
+ /* always unload the driver */
+ /* but don't mask last error */
+ kern_return_t unload_err = UsbUnloadClassDriver( &printer );
+ if ( kIOReturnSuccess == kr )
+ kr = unload_err;
+ }
+ }
+ }
+
+ printerInfo = UsbCopyPrinter( &printer );
+ if ( NULL != printerInfo )
+ CFArrayAppendValue( printers, (const void *) printerInfo ); /* keep track of it */
+
+ } /* if there's a printer */
+ kr = (*intf)->Release(intf);
+ } /* if IOCreatePlugInInterfaceForService */
+
+ IOObjectRelease(usbInterface);
+ usbInterface = NULL;
+
+ } /* while there's an interface */
+ } while ( 0 );
+
+ if (iter)
+ {
+ IOObjectRelease(iter);
+ iter = 0;
+ }
+
+ if (master_device_port)
+ {
+ mach_port_deallocate(mach_task_self(), master_device_port);
+ master_device_port = 0;
+ }
+ return printers;
+
+} /* UsbGetAllPrinters */
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Method: UsbReleasePrinter
+
+ Input Parameters:
+
+ Output Parameters:
+
+ Description:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+void
+UsbReleasePrinter( USBPrinterInfo *printer )
+{
+ if ( printer )
+ {
+ UsbUnloadClassDriver( printer );
+ if ( NULL != printer->address.manufacturer )
+ CFRelease( printer->address.manufacturer );
+ if ( NULL != printer->address.product )
+ CFRelease( printer->address.product );
+ if ( NULL != printer->address.serial )
+ CFRelease( printer->address.serial );
+ if ( NULL != printer->address.command )
+ CFRelease( printer->address.command );
+ if ( NULL != printer->bundle )
+ CFRelease( printer->bundle );
+ free( printer );
+ }
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Method: UsbReleaseAllPrinters
+
+ Input Parameters:
+
+ Output Parameters:
+
+ Description:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+void
+UsbReleaseAllPrinters( CFMutableArrayRef printers )
+{
+ if ( NULL != printers )
+ {
+ CFIndex i,
+ numPrinters = CFArrayGetCount(printers);
+ for ( i = 0; i < numPrinters; ++i )
+ UsbReleasePrinter( (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i ) );
+ CFRelease( printers );
+ }
+}
+
+USBPrinterInfo *
+UsbCopyPrinter( USBPrinterInfo *aPrinter )
+{
+ /* */
+ /* note this does not copy interface information, just address information */
+ /* */
+ USBPrinterInfo *printerInfo = (USBPrinterInfo *) calloc( 1, sizeof(USBPrinterInfo));
+ if ( NULL != printerInfo && NULL != aPrinter )
+ {
+ printerInfo->location = aPrinter->location;
+ if ( NULL != (printerInfo->address.manufacturer = aPrinter->address.manufacturer) )
+ CFRetain( printerInfo->address.manufacturer );
+ if ( NULL != (printerInfo->address.product = aPrinter->address.product) )
+ CFRetain( printerInfo->address.product );
+ if ( NULL != (printerInfo->address.serial = aPrinter->address.serial) )
+ CFRetain( printerInfo->address.serial );
+ if ( NULL != (printerInfo->address.command = aPrinter->address.command) )
+ CFRetain( printerInfo->address.command );
+ if ( NULL != (printerInfo->bundle = aPrinter->bundle) )
+ CFRetain( printerInfo->bundle );
+ }
+
+ return printerInfo;
+}
+
+/*-----------------------------------------------------------------------------*
+
+ UsbRegistryOpen
+
+ Desc: opens the USB printer which matches the supplied printerAddress
+
+ In: myContext->printerAddress persistent name which identifies the printer
+
+ Out: myContext->usbDeviceRef current IOKit address of this printer
+*-----------------------------------------------------------------------------*/
+kern_return_t
+UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result )
+{
+ kern_return_t kr = -1; /* indeterminate failure */
+ CFMutableArrayRef printers = UsbGetAllPrinters();
+ CFIndex numPrinters = NULL != printers? CFArrayGetCount( printers): 0;
+ CFIndex i;
+
+ *result = NULL; /* nothing matched */
+ for ( i = 0; i < numPrinters; ++i )
+ {
+ USBPrinterInfo *thisPrinter = (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i );
+ if ( NULL != thisPrinter && UsbSamePrinter( usbAddress, &thisPrinter->address ) )
+ {
+ *result = UsbCopyPrinter( thisPrinter ); /* retains reference */
+ if ( NULL != *result )
+ {
+ /* */
+ /* if we can't find a bi-di interface, settle for a known uni-directional interface */
+ /* */
+ USBPrinterClassContext **printer = NULL;
+ /* */
+ /* setup the default class driver */
+ /* If one is specified, allow the vendor driver to override our default implementation */
+ /* */
+ kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, NULL );
+ if ( kIOReturnSuccess == kr && (*result)->bundle )
+ kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, (*result)->bundle );
+ if ( kIOReturnSuccess == kr && NULL != (*result)->classdriver )
+ {
+ printer = (*result)->classdriver;
+ kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolBidirectional );
+ if ( kIOReturnSuccess != kr || NULL == (*printer)->interface )
+ kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolUnidirectional );
+ /* it's possible kIOReturnSuccess == kr && NULL == (*printer)->interface */
+ /* in the event that we can't open either Bidirectional or Unidirectional interface */
+ if ( kIOReturnSuccess == kr )
+ {
+ if ( NULL == (*printer)->interface )
+ {
+ (*printer)->Close( printer );
+ UsbReleasePrinter( *result );
+ *result = NULL;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ UsbReleaseAllPrinters( printers ); /* but, copied printer is retained */
+ DEBUG_ERR( kr, "UsbRegistryOpen return %x\n" );
+
+ return kr;
+}
+
+/*!
+ * @function CreateEncodedCFString
+ *
+ * @abstract Create an encoded version of the string parameter
+ * so that it can be included in a URI.
+ *
+ * @param string A CFStringRef of the string to be encoded.
+ * @result An encoded CFString.
+ *
+ * @discussion This function will change all characters in string into URL acceptable format
+ * by encoding the text using the US-ASCII coded character set. The following
+ * are invalid characters: the octets 00-1F, 7F, and 80-FF hex. Also called out
+ * are the chars "<", ">", """, "#", "{", "}", "|", "\", "^", "~", "[", "]", "`".
+ * The reserved characters for URL syntax are also to be encoded: (so don't pass
+ * in a full URL here!) ";", "/", "?", ":", "@", "=", "%", and "&".
+ */
+static CFStringRef CreateEncodedCFString(CFStringRef string)
+{
+ CFStringRef result = NULL;
+ char *bufferUTF8 = NULL;
+ char *bufferEncoded = NULL;
+
+ if (string != NULL)
+ {
+ CFIndex bufferSizeUTF8 = (3 * CFStringGetLength(string));
+ if ((bufferUTF8 = (char*)malloc(bufferSizeUTF8)) != NULL)
+ {
+ CFStringGetCString(string, bufferUTF8, bufferSizeUTF8, kCFStringEncodingUTF8);
+ {
+ UInt16 bufferSizeEncoded = (3 * strlen(bufferUTF8)) + 1;
+ if ((bufferEncoded = (char*)malloc(bufferSizeEncoded)) != NULL)
+ {
+ addPercentEscapes(bufferUTF8, bufferEncoded, bufferSizeEncoded);
+ result = CFStringCreateWithCString(kCFAllocatorDefault, bufferEncoded, kCFStringEncodingUTF8);
+ }
+ }
+ }
+ }
+
+ if (bufferUTF8) free(bufferUTF8);
+ if (bufferEncoded) free(bufferEncoded);
+
+ return result;
+}
+
+/*
+ * End of "$Id: usb-darwin.c 4548 2005-06-27 02:33:50Z mike $".
+ */
diff --git a/backend/usb-unix.c b/backend/usb-unix.c
new file mode 100644
index 000000000..4470e9c65
--- /dev/null
+++ b/backend/usb-unix.c
@@ -0,0 +1,620 @@
+/*
+ * "$Id: usb-unix.c 4881 2005-12-15 22:03:40Z mike $"
+ *
+ * USB port backend for the Common UNIX Printing System (CUPS).
+ *
+ * This file is included from "usb.c" when compiled on UNIX/Linux.
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Send a file to the specified USB port.
+ * list_devices() - List all USB devices.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "ieee1284.c"
+#include
+
+
+/*
+ * Local functions...
+ */
+
+int open_device(const char *uri);
+
+
+/*
+ * 'print_device()' - Print a file to a USB device.
+ */
+
+int /* O - Exit status */
+print_device(const char *uri, /* I - Device URI */
+ const char *hostname, /* I - Hostname/manufacturer */
+ const char *resource, /* I - Resource/modelname */
+ const char *options, /* I - Device options/serial number */
+ int fp, /* I - File descriptor to print */
+ int copies) /* I - Copies to print */
+{
+ int fd; /* USB device */
+ int rbytes; /* Number of bytes read */
+ 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 */
+ backbuf[1024]; /* Backchannel buffer */
+ struct termios opts; /* Parallel port options */
+ fd_set input, /* Input set for select() */
+ output; /* Output set for select() */
+ int paperout; /* Paper out? */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#ifdef __linux
+ unsigned int status; /* Port status (off-line, out-of-paper, etc.) */
+#endif /* __linux */
+
+
+ /*
+ * Open the USB port device...
+ */
+
+ do
+ {
+ if ((fd = open_device(uri)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ fputs("INFO: Unable to open USB device, queuing on next printer in class...\n",
+ stderr);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else if (errno == ENXIO || errno == EIO || errno == ENOENT || errno == ENODEV)
+ {
+ fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
+ uri, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ 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);
+
+ /*
+ * Check printer status...
+ */
+
+ paperout = 0;
+
+#if defined(__linux) && defined(LP_POUTPA)
+ /*
+ * Show the printer status before we send the file...
+ */
+
+ while (!ioctl(fd, LPGETSTATUS, &status))
+ {
+ fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
+
+ if (status & LP_POUTPA)
+ {
+ fputs("WARNING: Media tray empty!\n", stderr);
+ fputs("STATUS: +media-tray-empty-error\n", stderr);
+
+ paperout = 1;
+ }
+
+ if (!(status & LP_PERRORP))
+ fputs("WARNING: Printer fault!\n", stderr);
+ else if (!(status & LP_PSELECD))
+ fputs("WARNING: Printer off-line.\n", stderr);
+ else
+ break;
+
+ sleep(5);
+ }
+#endif /* __linux && LP_POUTPA */
+
+ /*
+ * 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... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (!fp)
+ {
+#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...
+ */
+
+ wbytes = 0;
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (fp != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(fp, 0, SEEK_SET);
+ }
+
+ tbytes = 0;
+ while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ /*
+ * See if we are ready to read or write...
+ */
+
+ do
+ {
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+ FD_ZERO(&output);
+ FD_SET(fd, &output);
+ }
+ while (select(fd + 1, &input, &output, NULL, NULL) < 0);
+
+ if (FD_ISSET(fd, &input))
+ {
+ /*
+ * Read backchannel data...
+ */
+
+ if ((rbytes = read(fd, backbuf, sizeof(backbuf))) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(backbuf, rbytes, 1.0);
+ }
+ }
+
+ if (FD_ISSET(fd, &output))
+ {
+ /*
+ * Write print data...
+ */
+
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ /*
+ * Check for retryable errors...
+ */
+
+ if (errno == ENOSPC)
+ {
+ paperout = 1;
+ fputs("ERROR: Out of paper!\n", stderr);
+ fputs("STATUS: +media-tray-empty-error\n", stderr);
+ }
+ else if (errno != EAGAIN && errno != EINTR)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Update count and pointer...
+ */
+
+ if (paperout)
+ {
+ fputs("STATUS: -media-tray-empty-error\n", stderr);
+ paperout = 0;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+ }
+ }
+
+ if (wbytes < 0)
+ break;
+
+ if (fp)
+ fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
+ (unsigned long)tbytes);
+ }
+ }
+
+ /*
+ * Close the USB port and return...
+ */
+
+ close(fd);
+
+ return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'list_devices()' - List all USB devices.
+ */
+
+void
+list_devices(void)
+{
+#ifdef __linux
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char format[255], /* Format for device filename */
+ device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ device_uri[1024], /* Device URI string */
+ make_model[1024]; /* Make and model */
+
+
+ /*
+ * First figure out which USB printer filename to use...
+ */
+
+ if (!access("/dev/usblp0", 0))
+ strcpy(format, "/dev/usblp%d");
+ else if (!access("/dev/usb/usblp0", 0))
+ strcpy(format, "/dev/usb/usblp%d");
+ else
+ strcpy(format, "/dev/usb/lp%d");
+
+ /*
+ * Then open each USB device...
+ */
+
+ for (i = 0; i < 16; i ++)
+ {
+ sprintf(device, format, i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
+ {
+ if (!get_device_id(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri)))
+ printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
+ make_model, make_model, i + 1, device_id);
+
+ close(fd);
+ }
+ }
+#elif defined(__sgi)
+#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ device_uri[1024], /* Device URI string */
+ make_model[1024]; /* Make and model */
+ struct ecpp_device_id did; /* Device ID buffer */
+
+
+ /*
+ * Open each USB device...
+ */
+
+ for (i = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/usb/printer%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
+ {
+ if (!get_device_id(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri)))
+ printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
+ make_model, make_model, i + 1, device_id);
+
+ close(fd);
+ }
+ }
+#elif defined(__hpux)
+#elif defined(__osf)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ int i; /* Looping var */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/ulpt%d", i);
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+
+ sprintf(device, "/dev/unlpt%d", i);
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
+ }
+#endif
+}
+
+
+/*
+ * 'open_device()' - Open a USB device...
+ */
+
+int /* O - File descriptor or -1 on error */
+open_device(const char *uri) /* I - Device URI */
+{
+ /*
+ * The generic implementation just treats the URI as a device filename...
+ * Specific operating systems may also support using the device serial
+ * number and/or make/model.
+ */
+
+ if (!strncmp(uri, "usb:/dev/", 9))
+#ifdef __linux
+ return (-1); /* Do not allow direct devices anymore */
+ else if (!strncmp(uri, "usb://", 6))
+ {
+ /*
+ * For Linux, try looking up the device serial number or model...
+ */
+
+ int i; /* Looping var */
+ int busy; /* Are any ports busy? */
+ int fd; /* File descriptor */
+ char format[255], /* Format for device filename */
+ device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ make_model[1024], /* Make and model */
+ device_uri[1024]; /* Device URI string */
+
+
+ /*
+ * First figure out which USB printer filename to use...
+ */
+
+ if (!access("/dev/usblp0", 0))
+ strcpy(format, "/dev/usblp%d");
+ else if (!access("/dev/usb/usblp0", 0))
+ strcpy(format, "/dev/usb/usblp%d");
+ else
+ strcpy(format, "/dev/usb/lp%d");
+
+ /*
+ * Then find the correct USB device...
+ */
+
+ do
+ {
+ for (busy = 0, i = 0; i < 16; i ++)
+ {
+ sprintf(device, format, i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
+ {
+ get_device_id(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri));
+ }
+ else
+ {
+ /*
+ * If the open failed because it was busy, flag it so we retry
+ * as needed...
+ */
+
+ if (errno == EBUSY)
+ busy = 1;
+
+ device_uri[0] = '\0';
+ }
+
+ if (!strcmp(uri, device_uri))
+ {
+ /*
+ * Yes, return this file descriptor...
+ */
+
+ fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
+
+ return (fd);
+ }
+
+ /*
+ * This wasn't the one...
+ */
+
+ if (fd >= 0)
+ close(fd);
+ }
+
+ /*
+ * If we get here and at least one of the printer ports showed up
+ * as "busy", then sleep for a bit and retry...
+ */
+
+ if (busy)
+ {
+ fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
+ stderr);
+ sleep(5);
+ }
+ }
+ while (busy);
+
+ /*
+ * Couldn't find the printer, return "no such device or address"...
+ */
+
+ errno = ENODEV;
+
+ return (-1);
+ }
+#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
+ return (-1); /* Do not allow direct devices anymore */
+ else if (!strncmp(uri, "usb://", 6))
+ {
+ /*
+ * For Solaris, try looking up the device serial number or model...
+ */
+
+ int i; /* Looping var */
+ int busy; /* Are any ports busy? */
+ int fd; /* File descriptor */
+ char device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ make_model[1024], /* Make and model */
+ device_uri[1024]; /* Device URI string */
+ struct ecpp_device_id did; /* Device ID buffer */
+
+
+ /*
+ * Find the correct USB device...
+ */
+
+ do
+ {
+ for (i = 0, busy = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/usb/printer%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
+ get_device_id(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri));
+ else
+ {
+ /*
+ * If the open failed because it was busy, flag it so we retry
+ * as needed...
+ */
+
+ if (errno == EBUSY)
+ busy = 1;
+
+ device_uri[0] = '\0';
+ }
+
+ if (!strcmp(uri, device_uri))
+ return (fd); /* Yes, return this file descriptor... */
+
+ /*
+ * This wasn't the one...
+ */
+
+ if (fd >= 0)
+ close(fd);
+ }
+
+ /*
+ * If we get here and at least one of the printer ports showed up
+ * as "busy", then sleep for a bit and retry...
+ */
+
+ if (busy)
+ {
+ fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
+ stderr);
+ sleep(5);
+ }
+ }
+ while (busy);
+
+ /*
+ * Couldn't find the printer, return "no such device or address"...
+ */
+
+ errno = ENODEV;
+
+ return (-1);
+ }
+#else
+ return (open(uri + 4, O_RDWR | O_EXCL));
+#endif /* __linux */
+ else
+ {
+ errno = ENODEV;
+ return (-1);
+ }
+}
+
+
+/*
+ * End of "$Id: usb-unix.c 4881 2005-12-15 22:03:40Z mike $".
+ */
diff --git a/backend/usb.c b/backend/usb.c
new file mode 100644
index 000000000..3ffe2d0d1
--- /dev/null
+++ b/backend/usb.c
@@ -0,0 +1,273 @@
+/*
+ * "$Id: usb.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * USB port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * list_devices() - List all available USB devices to stdout.
+ * print_device() - Print a file to a USB device.
+ * main() - Send a file to the specified USB port.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#ifdef __APPLE__
+ /* A header order dependency requires this be first */
+# include
+#endif /* __APPLE__ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+# include
+#else
+# include
+# include
+# include
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+void list_devices(void);
+int print_device(const char *uri, const char *hostname,
+ const char *resource, const char *options,
+ int fp, int copies);
+
+
+/*
+ * Include the vendor-specific USB implementation...
+ */
+
+#ifdef __APPLE__
+# include "usb-darwin.c"
+#elif defined(__linux) || defined(__sun) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+# include "usb-unix.c"
+#else
+/*
+ * Use dummy functions that do nothing on unsupported platforms...
+ * These can be used as templates for implementing USB printing on new
+ * platforms...
+ */
+
+/*
+ * 'list_devices()' - List all available USB devices to stdout.
+ */
+
+void
+list_devices(void)
+{
+ /*
+ * Don't have any devices to list... Use output of the form:
+ *
+ * direct usb:/make/model?serial=foo "Make Model" "USB Printer"
+ *
+ * Note that "Hewlett Packard" or any other variation MUST be mapped to
+ * "HP" for compatibility with the PPD and ICC specs.
+ */
+}
+
+
+/*
+ * 'print_device()' - Print a file to a USB device.
+ */
+
+int /* O - Exit status */
+print_device(const char *uri, /* I - Device URI */
+ const char *hostname, /* I - Hostname/manufacturer */
+ const char *resource, /* I - Resource/modelname */
+ const char *options, /* I - Device options/serial number */
+ int fp, /* I - File descriptor to print */
+ int copies) /* I - Copies to print */
+{
+ /*
+ * Can't print, so just reference the arguments to eliminate compiler
+ * warnings and return and exit status of 1. Normally you would use the
+ * arguments to send a file to the printer and return 0 if everything
+ * worked OK and non-zero if there was an error.
+ */
+
+ (void)uri;
+ (void)hostname;
+ (void)resource;
+ (void)options;
+ (void)fp;
+ (void)copies;
+
+ return (CUPS_BACKEND_FAILED);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * '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 */
+{
+ int fp; /* Print file */
+ int copies; /* Number of copies to print */
+ int status; /* Exit status */
+ int port; /* Port number (not used) */
+ const char *uri; /* Device URI */
+ 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 */
+#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);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ list_devices();
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ fputs("Usage: usb job-id user title copies options [file]\n", stderr);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ if (strncmp(argv[0], "usb:", 4))
+ uri = getenv("DEVICE_URI");
+ else
+ uri = argv[0];
+
+ if (!uri)
+ {
+ fputs("ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable!\n", stderr);
+ return (1);
+ }
+
+ httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(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';
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ fp = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = open(argv[6], O_RDONLY)) < 0)
+ {
+ fprintf(stderr, "ERROR: unable to open print file %s - %s\n",
+ argv[6], strerror(errno));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Finally, send the print file...
+ */
+
+ status = print_device(uri, hostname, resource, options, fp, copies);
+
+ /*
+ * Close the input file and return...
+ */
+
+ if (fp != 0)
+ close(fp);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id: usb.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/berkeley/Dependencies b/berkeley/Dependencies
new file mode 100644
index 000000000..ceb85278c
--- /dev/null
+++ b/berkeley/Dependencies
@@ -0,0 +1,14 @@
+# DO NOT DELETE
+
+lpc.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h
+lpc.o: ../cups/ppd.h ../cups/file.h ../cups/i18n.h ../cups/language.h
+lpc.o: ../cups/array.h ../cups/debug.h ../cups/string.h ../config.h
+lpq.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
+lpq.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h
+lpq.o: ../cups/i18n.h ../cups/language.h ../cups/array.h ../cups/debug.h
+lpr.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
+lpr.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h
+lpr.o: ../cups/i18n.h ../cups/language.h ../cups/array.h
+lprm.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h
+lprm.o: ../cups/ppd.h ../cups/file.h ../cups/i18n.h ../cups/language.h
+lprm.o: ../cups/array.h ../cups/string.h ../config.h
diff --git a/berkeley/Makefile b/berkeley/Makefile
new file mode 100644
index 000000000..454f6d657
--- /dev/null
+++ b/berkeley/Makefile
@@ -0,0 +1,112 @@
+#
+# "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $"
+#
+# Berkeley commands makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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)
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_BIN) lpq $(BINDIR)
+ $(INSTALL_BIN) lpr $(BINDIR)
+ $(INSTALL_BIN) lprm $(BINDIR)
+ $(INSTALL_DIR) $(SBINDIR)
+ $(INSTALL_BIN) lpc $(SBINDIR)
+
+
+#
+# lpc
+#
+
+lpc: lpc.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpc lpc.o $(LIBS)
+
+
+#
+# lpq
+#
+
+lpq: lpq.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpq lpq.o $(LIBS)
+
+
+#
+# lpr
+#
+
+lpr: lpr.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpr lpr.o $(LIBS)
+
+
+#
+# lprm
+#
+
+lprm: lprm.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lprm lprm.o $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $".
+#
diff --git a/berkeley/lpc.c b/berkeley/lpc.c
new file mode 100644
index 000000000..4b80a618d
--- /dev/null
+++ b/berkeley/lpc.c
@@ -0,0 +1,524 @@
+/*
+ * "$Id: lpc.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * "lpc" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * 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(const char *, const char *, int);
+static void do_command(http_t *, const char *, const char *);
+static void show_help(const char *);
+static void show_status(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 */
+{
+ http_t *http; /* Connection to server */
+ char line[1024], /* Input line from user */
+ *params; /* Pointer to parameters */
+
+
+ /*
+ * Connect to the scheduler...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ 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 trailing whitespace...
+ */
+
+ for (params = line + strlen(line) - 1; params >= line;)
+ if (!isspace(*params & 255))
+ break;
+ else
+ *params-- = '\0';
+
+ /*
+ * Strip leading whitespace...
+ */
+
+ for (params = line; isspace(*params & 255); params ++);
+
+ if (params > line)
+ _cups_strcpy(line, params);
+
+ if (!line[0])
+ {
+ /*
+ * Nothing left, just show a prompt...
+ */
+
+ printf("lpc> ");
+ continue;
+ }
+
+ /*
+ * Find any options in the string...
+ */
+
+ for (params = line; *params != '\0'; params ++)
+ if (isspace(*params & 255))
+ break;
+
+ /*
+ * Remove whitespace between the command and parameters...
+ */
+
+ while (isspace(*params & 255))
+ *params++ = '\0';
+
+ /*
+ * The "quit" and "exit" commands exit; otherwise, process as needed...
+ */
+
+ if (!compare_strings(line, "quit", 1) ||
+ !compare_strings(line, "exit", 2))
+ 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(const char *s, /* I - Command-line string */
+ const 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 */
+ const char *command, /* I - Command string */
+ const char *params) /* I - Parameters for command */
+{
+ if (!compare_strings(command, "status", 4))
+ show_status(http, params);
+ else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
+ show_help(params);
+ else
+ _cupsLangPrintf(stdout, cupsLangDefault(),
+ _("%s is not implemented by the CUPS version of lpc.\n"),
+ command);
+}
+
+
+/*
+ * 'show_help()' - Show help messages.
+ */
+
+static void
+show_help(const char *command) /* I - Command to describe or NULL */
+{
+ if (!command)
+ {
+ _cupsLangPrintf(stdout, cupsLangDefault(),
+ _("Commands may be abbreviated. Commands are:\n"
+ "\n"
+ "exit help quit status ?\n"));
+ }
+ else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
+ _cupsLangPrintf(stdout, cupsLangDefault(),
+ _("help\t\tget help on commands\n"));
+ else if (!compare_strings(command, "status", 4))
+ _cupsLangPrintf(stdout, cupsLangDefault(),
+ _("status\t\tshow status of daemon and queue\n"));
+ else
+ _cupsLangPrintf(stdout, cupsLangDefault(),
+ _("?Invalid help command unknown\n"));
+}
+
+
+/*
+ * 'show_status()' - Show printers.
+ */
+
+static void
+show_status(http_t *http, /* I - HTTP connection to server */
+ const 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 */
+ *delimiter; /* Char search result */
+ ipp_pstate_t pstate; /* Printer state */
+ int accepting; /* Is printer accepting jobs? */
+ int jobcount; /* Count of current jobs */
+ const 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(http=%p, dests=\"%s\")\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, "/")) != 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") &&
+ attr->value_tag == IPP_TAG_NAME)
+ printer = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "device-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ device = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "printer-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ pstate = (ipp_pstate_t)attr->values[0].integer;
+
+ if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
+ 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;
+ }
+
+ /*
+ * A single 'all' printer name is special, meaning all printers.
+ */
+
+ if (dests != NULL && !strcmp(dests, "all"))
+ dests = NULL;
+
+ /*
+ * 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 & 255) || *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 & 255)))
+ {
+ match = 1;
+ break;
+ }
+
+ /*
+ * Skip trailing junk...
+ */
+
+ while (!isspace(*dptr & 255) && *dptr != '\0')
+ dptr ++;
+ while (isspace(*dptr & 255) || *dptr == ',')
+ dptr ++;
+
+ if (*dptr == '\0')
+ break;
+ }
+ }
+
+ /*
+ * Display the printer entry if needed...
+ */
+
+ if (match)
+ {
+ /*
+ * 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);
+
+ httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL,
+ "localhost", 631, "/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, "/")) != NULL)
+ {
+ /*
+ * Grab the number of jobs for the printer.
+ */
+
+ for (jattr = jobs->attrs; jattr != NULL; jattr = jattr->next)
+ if (jattr->name && !strcmp(jattr->name, "job-id"))
+ jobcount ++;
+
+ ippDelete(jobs);
+ }
+
+ /*
+ * Display it...
+ */
+
+ printf("%s:\n", printer);
+ if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout, language,
+ _("\tprinter is on device \'%s\' speed -1\n"),
+ device + 5);
+ else
+ {
+ /*
+ * Just show the scheme...
+ */
+
+ if ((delimiter = strchr(device, ':')) != NULL )
+ {
+ *delimiter = '\0';
+ _cupsLangPrintf(stdout, language,
+ _("\tprinter is on device \'%s\' speed -1\n"),
+ device);
+ }
+ }
+
+ if (accepting)
+ _cupsLangPuts(stdout, language, _("\tqueuing is enabled\n"));
+ else
+ _cupsLangPuts(stdout, language, _("\tqueuing is disabled\n"));
+
+ if (pstate != IPP_PRINTER_STOPPED)
+ _cupsLangPuts(stdout, language, _("\tprinting is enabled\n"));
+ else
+ _cupsLangPuts(stdout, language, _("\tprinting is disabled\n"));
+
+ if (jobcount == 0)
+ _cupsLangPuts(stdout, language, _("\tno entries\n"));
+ else
+ _cupsLangPrintf(stdout, language, _("\t%d entries\n"), jobcount);
+
+ _cupsLangPuts(stdout, language, _("\tdaemon present\n"));
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * End of "$Id: lpc.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/berkeley/lpq.c b/berkeley/lpq.c
new file mode 100644
index 000000000..a5e009171
--- /dev/null
+++ b/berkeley/lpq.c
@@ -0,0 +1,640 @@
+/*
+ * "$Id: lpq.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * "lpq" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * 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.
+ * usage() - Show program usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#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 *);
+static void usage(void);
+
+
+/*
+ * '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 */
+ *val; /* Environment variable name */
+ char *instance; /* Printer instance */
+ int id, /* Desired job ID */
+ all, /* All printers */
+ interval, /* Reporting interval */
+ longstatus; /* Show file details */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ cups_lang_t *language; /* Language */
+#ifdef HAVE_SSL
+ http_encryption_t encryption; /* Encryption? */
+#endif /* HAVE_SSL */
+
+
+ language = cupsLangDefault();
+
+ /*
+ * Connect to the scheduler...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpq: Unable to contact server!\n"));
+ return (1);
+ }
+
+ /*
+ * Check for command-line options...
+ */
+
+ dest = NULL;
+ user = NULL;
+ id = 0;
+ interval = 0;
+ longstatus = 0;
+ all = 0;
+ num_dests = cupsGetDests(&dests);
+
+ 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_SSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ _cupsLangPrintf(stderr, language,
+ _("%s: Sorry, no encryption support compiled in!\n"),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'P' : /* Printer */
+ if (argv[i][2])
+ dest = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ httpClose(http);
+ cupsFreeDests(num_dests, dests);
+
+ usage();
+ }
+
+ dest = argv[i];
+ }
+
+ if ((instance = strchr(dest, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (cupsGetDest(dest, instance, num_dests, dests) == NULL)
+ {
+ if (instance)
+ _cupsLangPrintf(stderr, language,
+ _("lpq: Unknown destination \"%s/%s\"!\n"),
+ dest, instance);
+ else
+ _cupsLangPrintf(stderr, language,
+ _("lpq: Unknown destination \"%s\"!\n"), dest);
+
+ return (1);
+ }
+ break;
+
+ case 'a' : /* All printers */
+ all = 1;
+ break;
+
+ case 'l' : /* Long status */
+ longstatus = 1;
+ break;
+
+ default :
+ httpClose(http);
+ cupsFreeDests(num_dests, dests);
+
+ usage();
+ break;
+ }
+ }
+ else if (isdigit(argv[i][0] & 255))
+ id = atoi(argv[i]);
+ else
+ user = argv[i];
+
+ if (dest == NULL && !all)
+ {
+ for (i = 0; i < num_dests; i ++)
+ if (dests[i].is_default)
+ dest = dests[i].name;
+
+ if (dest == NULL)
+ {
+ val = NULL;
+
+ if ((dest = getenv("LPDEST")) == NULL)
+ {
+ if ((dest = getenv("PRINTER")) != NULL)
+ {
+ if (!strcmp(dest, "lp"))
+ dest = NULL;
+ else
+ val = "PRINTER";
+ }
+ }
+ else
+ val = "LPDEST";
+
+ if (dest && !cupsGetDest(dest, NULL, num_dests, dests))
+ _cupsLangPrintf(stderr, language,
+ _("lp: error - %s environment variable names "
+ "non-existent destination \"%s\"!\n"),
+ val, dest);
+ else
+ _cupsLangPuts(stderr, language,
+ _("lpq: error - no default destination available.\n"));
+ httpClose(http);
+ cupsFreeDests(num_dests, dests);
+ return (1);
+ }
+ }
+
+ /*
+ * 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
+ {
+ httpAssembleURIf(resource, sizeof(resource), "ipp", NULL, "localhost", 0,
+ "/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)
+ {
+ _cupsLangPrintf(stderr, language, _("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;
+
+#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__
+ _cupsLangPuts(stdout, language,
+ _("Rank Owner Pri Job Files"
+ " Total Size\n"));
+#else
+ _cupsLangPuts(stdout, language,
+ _("Rank Owner Job File(s)"
+ " Total Size\n"));
+#endif /* __osf__ */
+
+ jobcount ++;
+
+ /*
+ * Display the job...
+ */
+
+ if (jobstate == IPP_JOB_PROCESSING)
+ strcpy(rankstr, "active");
+ else
+ {
+ /*
+ * Make the rank show the "correct" suffix for each number
+ * (11-13 are the only special cases, for English anyways...)
+ */
+
+ if ((rank % 100) >= 11 && (rank % 100) <= 13)
+ snprintf(rankstr, sizeof(rankstr), "%dth", rank);
+ else
+ snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
+
+ rank ++;
+ }
+
+ if (longstatus)
+ {
+ _cupsLangPuts(stdout, language, "");
+
+ if (jobcopies > 1)
+ snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
+ jobname);
+ else
+ strlcpy(namestr, jobname, sizeof(namestr));
+
+ _cupsLangPrintf(stdout, language, _("%s: %-33.33s [job %d localhost]\n"),
+ jobuser, rankstr, jobid);
+ _cupsLangPrintf(stdout, language, _(" %-39.39s %.0f bytes\n"),
+ namestr, 1024.0 * jobsize);
+ }
+ else
+#ifdef __osf__
+ _cupsLangPrintf(stdout, language,
+ _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"),
+ rankstr, jobuser, jobpriority, jobid, jobname,
+ 1024.0 * jobsize);
+#else
+ _cupsLangPrintf(stdout, language,
+ _("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"),
+ rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
+#endif /* __osf */
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, language, _("lpq: get-jobs failed: %s\n"),
+ ippErrorString(cupsLastError()));
+ return (0);
+ }
+
+ if (jobcount == 0)
+ _cupsLangPuts(stdout, language, _("no entries\n"));
+
+ 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("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 :
+ _cupsLangPrintf(stdout, language, _("%s is ready\n"), dest);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ _cupsLangPrintf(stdout, language, _("%s is ready and printing\n"),
+ dest);
+ break;
+ case IPP_PRINTER_STOPPED :
+ _cupsLangPrintf(stdout, language, _("%s is not ready\n"), dest);
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ _cupsLangPrintf(stderr, language,
+ _("lpq: get-printer-attributes failed: %s\n"),
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stderr, cupsLangDefault(),
+ _("Usage: lpq [-P dest] [-l] [+interval]\n"));
+ exit(1);
+}
+
+
+/*
+ * End of "$Id: lpq.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/berkeley/lpr.c b/berkeley/lpr.c
new file mode 100644
index 000000000..58c9202f4
--- /dev/null
+++ b/berkeley/lpr.c
@@ -0,0 +1,495 @@
+/*
+ * "$Id: lpr.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * "lpr" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * 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
+#include
+#include
+
+#ifndef WIN32
+# include
+# 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 */
+ *val; /* Environment variable name */
+ 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 */
+ cups_lang_t *language; /* Language information */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Signal action */
+ struct sigaction oldaction; /* Old 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;
+ language = cupsLangDefault();
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (ch = argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr, language,
+ _("%s: Sorry, no encryption support compiled in!\n"),
+ argv[0]);
+#endif /* HAVE_SSL */
+ 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)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - 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 */
+ _cupsLangPrintf(stderr, language,
+ _("lpr: 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)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - expected option=value after "
+ "-o option!\n"));
+ 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 */
+ _cupsLangPuts(stderr, language,
+ _("lpr: warning - email notification is not "
+ "currently supported!\n"));
+ 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)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - expected destination after -P "
+ "option!\n"));
+ 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)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - expected copy count after -# "
+ "option!\n"));
+ return (1);
+ }
+
+ num_copies = atoi(argv[i]);
+ }
+
+ 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)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - 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)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - expected username after -U "
+ "option!\n"));
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - unknown option \'%c\'!\n"),
+ argv[i][1]);
+ return (1);
+ }
+ else if (num_files < 1000)
+ {
+ /*
+ * Print a file...
+ */
+
+ if (access(argv[i], R_OK) != 0)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - unable to access \"%s\" - %s\n"),
+ argv[i], strerror(errno));
+ return (1);
+ }
+
+ files[num_files] = argv[i];
+ num_files ++;
+
+ if (title == NULL)
+ {
+ if ((title = strrchr(argv[i], '/')) != NULL)
+ title ++;
+ else
+ title = argv[i];
+ }
+ }
+ else
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - 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);
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
+ {
+ printer = dest->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);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ val = NULL;
+
+ if ((printer = getenv("LPDEST")) == NULL)
+ {
+ if ((printer = getenv("PRINTER")) != NULL)
+ {
+ if (!strcmp(printer, "lp"))
+ printer = NULL;
+ else
+ val = "PRINTER";
+ }
+ }
+ else
+ val = "LPDEST";
+
+ if (printer && !cupsGetDest(printer, NULL, num_dests, dests))
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - %s environment variable names "
+ "non-existent destination \"%s\"!\n"),
+ val, printer);
+ else if (cupsLastError() == IPP_NOT_FOUND)
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - no default destination available.\n"));
+ else
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - scheduler not responding!\n"));
+
+ return (1);
+ }
+
+ if (num_files > 0)
+ {
+ job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
+
+ if (deletefile && job_id > 0)
+ {
+ /*
+ * 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);
+ if (sigset(SIGINT, sighandler) == SIG_IGN)
+ sigset(SIGINT, SIG_IGN);
+ sigset(SIGTERM, sighandler);
+# elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = sighandler;
+
+ sigaction(SIGHUP, &action, NULL);
+ sigaction(SIGINT, NULL, &oldaction);
+ if (oldaction.sa_handler != SIG_IGN)
+ sigaction(SIGINT, &action, NULL);
+ sigaction(SIGTERM, &action, NULL);
+# else
+ signal(SIGHUP, sighandler);
+ if (signal(SIGINT, sighandler) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, sighandler);
+# endif
+#endif /* !WIN32 */
+
+ if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - unable to create temporary file "
+ "\"%s\" - %s\n"),
+ tempfile, strerror(errno));
+ return (1);
+ }
+
+ while ((i = read(0, buffer, sizeof(buffer))) > 0)
+ if (write(temp, buffer, i) < 0)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - unable to write to temporary file "
+ "\"%s\" - %s\n"),
+ tempfile, strerror(errno));
+ close(temp);
+ unlink(tempfile);
+ return (1);
+ }
+
+ i = lseek(temp, 0, SEEK_CUR);
+ close(temp);
+
+ if (i == 0)
+ {
+ _cupsLangPuts(stderr, language,
+ _("lpr: error - stdin is empty, so no job has been sent.\n"));
+ unlink(tempfile);
+ 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)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lpr: error - 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: lpr.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/berkeley/lprm.c b/berkeley/lprm.c
new file mode 100644
index 000000000..f6fe9fc6b
--- /dev/null
+++ b/berkeley/lprm.c
@@ -0,0 +1,284 @@
+/*
+ * "$Id: lprm.c 4906 2006-01-10 20:53:28Z mike $"
+ *
+ * "lprm" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * 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();
+ language = cupsLangDefault();
+ 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 = httpConnectEncrypt(cupsServer(), ippPort(), encryption)) == NULL)
+ {
+ _cupsLangPuts(stderr, language, _("lprm: Unable to contact server!\n"));
+ cupsFreeDests(num_dests, dests);
+ return (1);
+ }
+
+ /*
+ * 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_SSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ httpEncryption(http, encryption);
+#else
+ _cupsLangPrintf(stderr, language,
+ _("%s: Sorry, no encryption support compiled in!\n"),
+ argv[0]);
+#endif /* HAVE_SSL */
+ 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';
+
+ if (cupsGetDest(dest, NULL, num_dests, dests) == NULL)
+ {
+ _cupsLangPrintf(stderr, language,
+ _("lprm: Unknown destination \"%s\"!\n"), dest);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ return(1);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, language,
+ _("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] & 255) &&
+ cupsGetDest(argv[i], NULL, num_dests, dests) == NULL)
+ {
+ 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;
+
+ 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)
+ {
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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 :
+ _cupsLangPuts(stderr, language,
+ _("lprm: Job or printer not found!\n"));
+ break;
+ case IPP_NOT_AUTHORIZED :
+ _cupsLangPuts(stderr, language,
+ _("lprm: Not authorized to lprm job(s)!\n"));
+ break;
+ case IPP_FORBIDDEN :
+ _cupsLangPrintf(stderr, language,
+ _("lprm: You don't own job ID %d!\n"), job_id);
+ break;
+ default :
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ _cupsLangPuts(stderr, language,
+ _("lprm: Unable to lprm job(s)!\n"));
+ break;
+ }
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ ippDelete(response);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPuts(stderr, language,
+ _("lprm: Unable to cancel job(s)!\n"));
+ 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))
+ {
+ _cupsLangPuts(stderr, language,
+ _("lprm: Unable to cancel job(s)!\n"));
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ return (1);
+ }
+
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: lprm.c 4906 2006-01-10 20:53:28Z mike $".
+ */
diff --git a/cgi-bin/Dependencies b/cgi-bin/Dependencies
new file mode 100644
index 000000000..fbcdc3d50
--- /dev/null
+++ b/cgi-bin/Dependencies
@@ -0,0 +1,50 @@
+# DO NOT DELETE
+
+help-index.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+help-index.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+help-index.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h
+help-index.o: ../cups/array.h ../cups/string.h ../config.h ../cups/dir.h
+html.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+html.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+html.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+html.o: ../cups/string.h ../config.h
+ipp-var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+ipp-var.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+ipp-var.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+ipp-var.o: ../cups/string.h ../config.h
+search.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+search.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+search.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+search.o: ../cups/string.h ../config.h
+template.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+template.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+template.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+template.o: ../cups/string.h ../config.h
+var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+var.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+var.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+var.o: ../cups/string.h ../config.h
+admin.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+admin.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+admin.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+admin.o: ../cups/string.h ../config.h ../cups/file.h
+classes.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+classes.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+classes.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+classes.o: ../cups/string.h ../config.h
+help.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+help.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+help.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+help.o: ../cups/string.h ../config.h
+jobs.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+jobs.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+jobs.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+jobs.o: ../cups/string.h ../config.h
+printers.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
+printers.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h
+printers.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h
+printers.o: ../cups/string.h ../config.h
+testcgi.o: cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h
+testcgi.o: ../cups/ppd.h ../cups/file.h help-index.h
+testhi.o: cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h
+testhi.o: ../cups/ppd.h ../cups/file.h help-index.h
diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile
new file mode 100644
index 000000000..fd218a306
--- /dev/null
+++ b/cgi-bin/Makefile
@@ -0,0 +1,151 @@
+#
+# "$Id: Makefile 4869 2005-12-06 02:43:40Z mike $"
+#
+# CGI makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+include ../Makedefs
+
+CGIS = admin.cgi classes.cgi help.cgi jobs.cgi printers.cgi
+TARGETS = libcgi.a $(CGIS) testcgi testhi
+LIBOBJS = help-index.o html.o ipp-var.o search.o template.o var.o
+OBJS = $(LIBOBJS) admin.o classes.o help.o \
+ jobs.o printers.o testcgi.o testhi.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS)
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all
+ $(INSTALL_DIR) $(SERVERBIN)/cgi-bin
+ for file in $(CGIS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/cgi-bin; \
+ done
+
+
+#
+# libcgi.a
+#
+
+libcgi.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# admin.cgi
+#
+
+admin.cgi: admin.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ admin.o libcgi.a $(LIBS)
+
+
+#
+# classes.cgi
+#
+
+classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ classes.o libcgi.a $(LIBS)
+
+
+#
+# help.cgi
+#
+
+help.cgi: help.o ../Makedefs libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ help.o libcgi.a $(LIBS)
+
+
+#
+# jobs.cgi
+#
+
+jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ jobs.o libcgi.a $(LIBS)
+
+
+#
+# printers.cgi
+#
+
+printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ printers.o libcgi.a $(LIBS)
+
+
+#
+# testcgi
+#
+
+testcgi: testcgi.o ../Makedefs libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testcgi.o libcgi.a $(LIBS)
+
+
+#
+# testhi
+#
+
+testhi: testhi.o ../Makedefs libcgi.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testhi.o libcgi.a $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id: Makefile 4869 2005-12-06 02:43:40Z mike $".
+#
diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
new file mode 100644
index 000000000..37be8beaa
--- /dev/null
+++ b/cgi-bin/admin.c
@@ -0,0 +1,3572 @@
+/*
+ * "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Administration CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ * compare_printer_devices() - Compare two printer devices.
+ * 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_config_server() - Configure server settings.
+ * do_delete_class() - Delete a class...
+ * do_delete_printer() - Delete a printer...
+ * do_menu() - Show the main menu...
+ * do_printer_op() - Do a printer operation.
+ * do_set_allowed_users() - Set the allowed/denied users for a queue.
+ * do_set_sharing() - Set printer-is-shared value...
+ * match_string() - Return the number of matching characters.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.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_config_server(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_menu(http_t *http, cups_lang_t *language);
+static void do_printer_op(http_t *http, cups_lang_t *language,
+ ipp_op_t op, const char *title);
+static void do_set_allowed_users(http_t *http, cups_lang_t *language);
+static void do_set_sharing(http_t *http, cups_lang_t *language);
+static int match_string(const char *a, const char *b);
+
+
+/*
+ * '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();
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "admin");
+
+ /*
+ * See if we have form data...
+ */
+
+ if (!cgiInitialize())
+ {
+ /*
+ * Nope, send the administration menu...
+ */
+
+ do_menu(http, language);
+ }
+ else if ((op = cgiGetVariable("OP")) != NULL)
+ {
+ /*
+ * Do the operation...
+ */
+
+ if (!strcmp(op, "redirect"))
+ {
+ const char *url; /* Redirection URL... */
+
+
+ if ((url = cgiGetVariable("URL")) != NULL)
+ printf("Location: %s\n\n", url);
+ else
+ puts("Location: /admin\n");
+ }
+ else if (!strcmp(op, "start-printer"))
+ do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Printer");
+ else if (!strcmp(op, "stop-printer"))
+ do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Printer");
+ else if (!strcmp(op, "start-class"))
+ do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Class");
+ else if (!strcmp(op, "stop-class"))
+ do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Class");
+ else if (!strcmp(op, "accept-jobs"))
+ do_printer_op(http, language, CUPS_ACCEPT_JOBS, "Accept Jobs");
+ else if (!strcmp(op, "reject-jobs"))
+ do_printer_op(http, language, CUPS_REJECT_JOBS, "Reject Jobs");
+ else if (!strcmp(op, "purge-jobs"))
+ do_printer_op(http, language, IPP_PURGE_JOBS, "Purge Jobs");
+ else if (!strcmp(op, "set-allowed-users"))
+ do_set_allowed_users(http, language);
+ else if (!strcmp(op, "set-as-default"))
+ do_printer_op(http, language, CUPS_SET_DEFAULT, "Set As Default");
+ else if (!strcmp(op, "set-sharing"))
+ do_set_sharing(http, language);
+ else if (!strcmp(op, "add-class"))
+ do_am_class(http, language, 0);
+ else if (!strcmp(op, "add-printer"))
+ do_am_printer(http, language, 0);
+ else if (!strcmp(op, "modify-class"))
+ do_am_class(http, language, 1);
+ else if (!strcmp(op, "modify-printer"))
+ do_am_printer(http, language, 1);
+ else if (!strcmp(op, "delete-class"))
+ do_delete_class(http, language);
+ else if (!strcmp(op, "delete-printer"))
+ do_delete_printer(http, language);
+ else if (!strcmp(op, "set-printer-options"))
+ do_config_printer(http, language);
+ else if (!strcmp(op, "config-server"))
+ do_config_server(http, language);
+ else
+ {
+ /*
+ * Bad operation code... Display an error...
+ */
+
+ cgiStartHTML("Error");
+ cgiCopyTemplateLang("admin-op.tmpl");
+ cgiEndHTML();
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+ }
+ else
+ {
+ /*
+ * Form data but no operation code... Display an error...
+ */
+
+ cgiStartHTML("Error");
+ cgiCopyTemplateLang("admin-op.tmpl");
+ cgiEndHTML();
+ }
+
+ /*
+ * Free the request language...
+ */
+
+ cupsLangFree(language);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'compare_printer_devices()' - Compare two printer devices.
+ */
+
+static int /* O - Result of comparison */
+compare_printer_devices(const void *a, /* I - First device */
+ const void *b) /* I - Second device */
+{
+ return (strcmp(*((char **)a), *((char **)b)));
+}
+
+
+/*
+ * '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 */
+ const char *title; /* Title of page */
+ static const char * const pattrs[] = /* Requested printer attributes */
+ {
+ "member-names",
+ "printer-info",
+ "printer-location"
+ };
+
+
+ title = modify ? "Modify Class" : "Add Class";
+ name = cgiGetVariable("PRINTER_NAME");
+
+ if (cgiGetVariable("PRINTER_LOCATION") == 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"))
+ {
+ if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
+ (!name || strcasecmp(name, ptr + 1)))
+ {
+ /*
+ * Don't show the current class...
+ */
+
+ 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"))
+ {
+ if (!name || strcasecmp(name, attr->values[0].string.text))
+ {
+ /*
+ * Don't show the current class...
+ */
+
+ cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
+ element ++;
+ }
+ }
+
+ num_printers = cgiGetSize("MEMBER_URIS");
+
+ ippDelete(response);
+ }
+ else
+ num_printers = 0;
+
+ 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/classes/%s", name);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(pattrs) / sizeof(pattrs[0])),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != 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 (!strcasecmp(attr->values[i].string.text,
+ cgiGetArray("MEMBER_NAMES", j)))
+ {
+ cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
+ break;
+ }
+ }
+ }
+ }
+
+ if ((attr = ippFindAttribute(response, "printer-info",
+ IPP_TAG_TEXT)) != NULL)
+ cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(response, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
+
+ ippDelete(response);
+ }
+
+ /*
+ * Update the location and description of an existing printer...
+ */
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("modify-class.tmpl");
+ }
+ else
+ {
+ /*
+ * Get the name, location, and description for a new printer...
+ */
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("add-class.tmpl");
+ }
+
+ cgiEndHTML();
+
+ return;
+ }
+
+ for (ptr = name; *ptr; ptr ++)
+ if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
+ break;
+
+ if (*ptr || ptr == name || strlen(name) > 127)
+ {
+ cgiSetVariable("ERROR", "The class name may only contain up to 127 printable "
+ "characters and may not contain spaces, slashes (/), "
+ "or the pound sign (#).");
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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 = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the class page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, name, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/classes/%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ if (modify)
+ cgiCopyTemplateLang("class-modified.tmpl");
+ else
+ cgiCopyTemplateLang("class-added.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * '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 cgi_file_t *file; /* Uploaded file, if any */
+ 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 */
+ const char *name, /* Pointer to class name */
+ *ptr; /* Pointer to CGI variable */
+ const char *title; /* Title of page */
+ static int baudrates[] = /* Baud rates */
+ {
+ 1200,
+ 2400,
+ 4800,
+ 9600,
+ 19200,
+ 38400,
+ 57600,
+ 115200,
+ 230400,
+ 460800
+ };
+
+
+ title = modify ? "Modify Printer" : "Add Printer";
+
+ 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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 ||
+ cgiGetVariable("PRINTER_LOCATION") == NULL)
+ {
+ cgiStartHTML(title);
+
+ if (modify)
+ {
+ /*
+ * Update the location and description of an existing printer...
+ */
+
+ if (oldinfo)
+ cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0);
+
+ cgiCopyTemplateLang("modify-printer.tmpl");
+ }
+ else
+ {
+ /*
+ * Get the name, location, and description for a new printer...
+ */
+
+ cgiCopyTemplateLang("add-printer.tmpl");
+ }
+
+ cgiEndHTML();
+
+ if (oldinfo)
+ ippDelete(oldinfo);
+
+ return;
+ }
+
+ for (ptr = name; *ptr; ptr ++)
+ if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
+ break;
+
+ if (*ptr || ptr == name || strlen(name) > 127)
+ {
+ cgiSetVariable("ERROR", "The printer name may only contain up to 127 printable "
+ "characters and may not contain spaces, slashes (/), "
+ "or the pound sign (#).");
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ file = cgiGetFile();
+
+ if (file)
+ {
+ fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
+ fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
+ fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
+ fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
+ }
+
+ 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)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+ }
+
+ /*
+ * Let the user choose...
+ */
+
+ if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
+ {
+ strlcpy(uri, attr->values[0].string.text, sizeof(uri));
+ if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
+ *uriptr = '\0';
+
+ cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
+ cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
+ }
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-device.tmpl");
+ cgiEndHTML();
+ }
+ else if (strchr(var, '/') == NULL)
+ {
+ if ((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...
+ */
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-uri.tmpl");
+ cgiEndHTML();
+ }
+ else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
+ {
+ /*
+ * 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);
+ }
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-serial.tmpl");
+ cgiEndHTML();
+ }
+ else if (!file && (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 */
+ http_status_t get_status; /* Status of GET */
+
+
+ snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
+
+ if (httpGet(http, uri))
+ httpGet(http, uri);
+
+ while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (get_status != HTTP_OK)
+ {
+ fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
+ uri, get_status, httpStatus(get_status));
+ }
+ else 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
+ {
+ fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
+ filename, ppdErrorString(ppdLastError(&bytes)));
+ }
+ }
+ else
+ {
+ httpFlush(http);
+
+ fprintf(stderr,
+ "ERROR: Unable to create temporary file for PPD file: %s\n",
+ strerror(errno));
+ }
+ }
+ else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL)
+ {
+ /*
+ * Extract make and make/model from device URI string...
+ */
+
+ char make[1024], /* Make string */
+ *makeptr; /* Pointer into make */
+
+
+ *uriptr++ = '\0';
+
+ strlcpy(make, uriptr, sizeof(make));
+
+ if ((makeptr = strchr(make, ' ')) != NULL)
+ *makeptr = '\0';
+ else if ((makeptr = strchr(make, '-')) != NULL)
+ *makeptr = '\0';
+ else if (!strncasecmp(make, "laserjet", 8) ||
+ !strncasecmp(make, "deskjet", 7) ||
+ !strncasecmp(make, "designjet", 9))
+ strcpy(make, "HP");
+ else if (!strncasecmp(make, "phaser", 6))
+ strcpy(make, "Xerox");
+ else if (!strncasecmp(make, "stylus", 6))
+ strcpy(make, "Epson");
+ else
+ strcpy(make, "Generic");
+
+ cgiSetVariable("CURRENT_MAKE", make);
+ cgiSetVariable("PPD_MAKE", make);
+ cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
+ }
+
+ /*
+ * 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/");
+
+
+ if ((var = cgiGetVariable("PPD_MAKE")) != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "ppd-make", NULL, var);
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "ppd-make");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Got the list of PPDs, see if the user has selected a make...
+ */
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ if (var == 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;
+ }
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-make.tmpl");
+ cgiEndHTML();
+ }
+ else
+ {
+ /*
+ * Let the user choose a model...
+ */
+
+ const char *make_model; /* Current make/model string */
+
+
+ if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
+ {
+ /*
+ * Scan for "close" matches...
+ */
+
+ int match, /* Current match */
+ best_match, /* Best match so far */
+ count; /* Number of drivers */
+ const char *best, /* Best matching string */
+ *current; /* Current string */
+
+
+ count = cgiGetSize("PPD_MAKE_AND_MODEL");
+
+ for (i = 0, best_match = 0, best = NULL; i < count; i ++)
+ {
+ current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
+ match = match_string(make_model, current);
+
+ if (match > best_match)
+ {
+ best_match = match;
+ best = current;
+ }
+ }
+
+ if (best_match > strlen(var))
+ {
+ /*
+ * Found a match longer than the make...
+ */
+
+ cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
+ }
+ }
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-model.tmpl");
+ cgiEndHTML();
+ }
+
+
+ ippDelete(response);
+ }
+ else
+ {
+ char message[1024];
+
+
+ snprintf(message, sizeof(message), "Unable to get list of printer drivers: %s",
+ ippErrorString(cupsLastError()));
+ cgiSetVariable("ERROR", message);
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ }
+ }
+ 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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"));
+
+ if (!file)
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
+ NULL, cgiGetVariable("PPD_NAME"));
+
+ strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
+
+ /*
+ * Strip make and model from URI...
+ */
+
+ if ((uriptr = strrchr(uri, '|')) != NULL)
+ *uriptr = '\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 (file)
+ response = cupsDoFileRequest(http, request, "/admin/", file->tempfile);
+ else
+ response = cupsDoRequest(http, request, "/admin/");
+
+ if (response)
+ {
+ status = response->request.status.status_code;
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer or set-options pages...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+
+ cgiFormEncode(uri, name, sizeof(uri));
+
+ if (modify)
+ snprintf(refresh, sizeof(refresh),
+ "5;/admin?OP=redirect&URL=/printers/%s", uri);
+ else
+ snprintf(refresh, sizeof(refresh),
+ "5;/admin?OP=set-printer-options&PRINTER_NAME=%s", uri);
+
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ if (modify)
+ cgiCopyTemplateLang("printer-modified.tmpl");
+ else
+ cgiCopyTemplateLang("printer-added.tmpl");
+ }
+
+ cgiEndHTML();
+ }
+
+ 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, m; /* 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 */
+ cups_file_t *in, /* Input file */
+ *out; /* Output file */
+ 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 */
+ ppd_attr_t *protocol; /* cupsProtocol attribute */
+
+
+ /*
+ * Get the printer name...
+ */
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Get the PPD file...
+ */
+
+ if ((filename = cupsGetPPD(printer)) == NULL)
+ {
+ if (cupsLastError() == IPP_NOT_FOUND)
+ {
+ /*
+ * No PPD file for this printer, so we can't configure it!
+ */
+
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_POSSIBLE));
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ }
+ else
+ {
+ /*
+ * Unable to access the PPD file for some reason...
+ */
+
+ cgiSetVariable("ERROR", ippErrorString(cupsLastError()));
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ }
+ return;
+ }
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_DEVICE_ERROR));
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if (cgiGetVariable("job_sheets_start") != NULL ||
+ cgiGetVariable("job_sheets_end") != NULL)
+ have_options = 1;
+ else
+ have_options = 0;
+
+ ppdMarkDefaults(ppd);
+
+ DEBUG_printf(("ppd->num_groups = %d\n"
+ "
\n", ppd->num_groups));
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ {
+ DEBUG_printf(("- %s
\n", group->text));
+
+ for (j = group->num_options, option = group->options; j > 0; j --, option ++)
+ if ((var = cgiGetVariable(option->keyword)) != NULL)
+ {
+ DEBUG_printf(("- %s = \"%s\"
\n", option->keyword, var));
+ have_options = 1;
+ ppdMarkOption(ppd, option->keyword, var);
+ }
+#ifdef DEBUG
+ else
+ printf("- %s not defined!
\n", option->keyword);
+#endif /* DEBUG */
+
+ DEBUG_puts("
");
+ }
+
+ DEBUG_printf(("
\n"
+ "ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
+
+ if (!have_options || ppdConflicts(ppd))
+ {
+ /*
+ * Show the options to the user...
+ */
+
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("set-printer-options-header.tmpl");
+
+ if (ppdConflicts(ppd))
+ {
+ for (i = ppd->num_groups, k = 0, group = ppd->groups; i > 0; i --, group ++)
+ for (j = group->num_options, option = group->options; j > 0; j --, option ++)
+ if (option->conflicted)
+ {
+ cgiSetArray("ckeyword", k, option->keyword);
+ cgiSetArray("ckeytext", k, option->text);
+ k ++;
+ }
+
+ cgiCopyTemplateLang("option-conflict.tmpl");
+ }
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0;
+ i --, group ++)
+ {
+ if (!strcmp(group->name, "InstallableOptions"))
+ cgiSetVariable("GROUP",
+ _cupsLangString(language, _("Options Installed")));
+ else
+ cgiSetVariable("GROUP", group->text);
+
+ cgiCopyTemplateLang("option-header.tmpl");
+
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ {
+ if (!strcmp(option->keyword, "PageRegion"))
+ continue;
+
+ cgiSetVariable("KEYWORD", option->keyword);
+ cgiSetVariable("KEYTEXT", option->text);
+
+ if (option->conflicted)
+ cgiSetVariable("CONFLICTED", "1");
+ else
+ cgiSetVariable("CONFLICTED", "0");
+
+ cgiSetSize("CHOICES", 0);
+ cgiSetSize("TEXT", 0);
+ for (k = 0, m = 0; k < option->num_choices; k ++)
+ {
+ /*
+ * Hide custom option values...
+ */
+
+ if (!strcmp(option->choices[k].choice, "Custom"))
+ continue;
+
+ cgiSetArray("CHOICES", m, option->choices[k].choice);
+ cgiSetArray("TEXT", m, option->choices[k].text);
+
+ m ++;
+
+ if (option->choices[k].marked)
+ cgiSetVariable("DEFCHOICE", option->choices[k].choice);
+ }
+
+ switch (option->ui)
+ {
+ case PPD_UI_BOOLEAN :
+ cgiCopyTemplateLang("option-boolean.tmpl");
+ break;
+ case PPD_UI_PICKONE :
+ cgiCopyTemplateLang("option-pickone.tmpl");
+ break;
+ case PPD_UI_PICKMANY :
+ cgiCopyTemplateLang("option-pickmany.tmpl");
+ break;
+ }
+ }
+
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ /*
+ * 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", 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)
+ {
+ if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Add the job sheets options...
+ */
+
+ cgiSetVariable("GROUP", "Banners");
+ cgiCopyTemplateLang("option-header.tmpl");
+
+ 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("option-pickone.tmpl");
+
+ cgiSetVariable("KEYWORD", "job_sheets_end");
+ cgiSetVariable("KEYTEXT", "Ending Banner");
+ cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
+ "" : attr->values[1].string.text);
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ if (ippFindAttribute(response, "printer-error-policy-supported",
+ IPP_TAG_ZERO) ||
+ ippFindAttribute(response, "printer-op-policy-supported",
+ IPP_TAG_ZERO))
+ {
+ /*
+ * Add the error and operation policy options...
+ */
+
+ cgiSetVariable("GROUP", "Policies");
+ cgiCopyTemplateLang("option-header.tmpl");
+
+ /*
+ * Error policy...
+ */
+
+ attr = ippFindAttribute(response, "printer-error-policy-supported",
+ IPP_TAG_ZERO);
+
+ if (attr)
+ {
+ 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, "printer-error-policy",
+ IPP_TAG_ZERO);
+
+ cgiSetVariable("KEYWORD", "printer_error_policy");
+ cgiSetVariable("KEYTEXT", "Error Policy");
+ cgiSetVariable("DEFCHOICE", attr == NULL ?
+ "" : attr->values[0].string.text);
+ }
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+
+ /*
+ * Operation policy...
+ */
+
+ attr = ippFindAttribute(response, "printer-op-policy-supported",
+ IPP_TAG_ZERO);
+
+ if (attr)
+ {
+ 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, "printer-op-policy", IPP_TAG_ZERO);
+
+ cgiSetVariable("KEYWORD", "printer_op_policy");
+ cgiSetVariable("KEYTEXT", "Operation Policy");
+ cgiSetVariable("DEFCHOICE", attr == NULL ?
+ "" : attr->values[0].string.text);
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+ }
+
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Binary protocol support...
+ */
+
+ if (ppd->protocols && strstr(ppd->protocols, "BCP"))
+ {
+ protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
+
+ cgiSetVariable("GROUP", "PS Binary Protocol");
+ cgiCopyTemplateLang("option-header.tmpl");
+
+ cgiSetSize("CHOICES", 2);
+ cgiSetSize("TEXT", 2);
+ cgiSetArray("CHOICES", 0, "None");
+ cgiSetArray("TEXT", 0, "None");
+
+ if (strstr(ppd->protocols, "TBCP"))
+ {
+ cgiSetArray("CHOICES", 1, "TBCP");
+ cgiSetArray("TEXT", 1, "TBCP");
+ }
+ else
+ {
+ cgiSetArray("CHOICES", 1, "BCP");
+ cgiSetArray("TEXT", 1, "BCP");
+ }
+
+ cgiSetVariable("KEYWORD", "protocol");
+ cgiSetVariable("KEYTEXT", "PS Binary Protocol");
+ cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
+ cgiEndHTML();
+ }
+ else
+ {
+ /*
+ * Set default options...
+ */
+
+ out = cupsTempFile2(tempfile, sizeof(tempfile));
+ in = cupsFileOpen(filename, "r");
+
+ if (!in || !out)
+ {
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiStartHTML("Set Printer Options");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ if (in)
+ cupsFileClose(in);
+
+ if (out)
+ {
+ cupsFileClose(out);
+ unlink(tempfile);
+ }
+
+ unlink(filename);
+ return;
+ }
+
+ while (cupsFileGets(in, line, sizeof(line)))
+ {
+ if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
+ continue;
+ else if (strncmp(line, "*Default", 8))
+ cupsFilePrintf(out, "%s\n", line);
+ else
+ {
+ /*
+ * Get default option name...
+ */
+
+ strlcpy(keyword, line + 8, sizeof(keyword));
+
+ for (keyptr = keyword; *keyptr; keyptr ++)
+ if (*keyptr == ':' || isspace(*keyptr & 255))
+ break;
+
+ *keyptr = '\0';
+
+ if (!strcmp(keyword, "PageRegion"))
+ var = cgiGetVariable("PageSize");
+ else
+ var = cgiGetVariable(keyword);
+
+ if (var != NULL)
+ cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
+ else
+ cupsFilePrintf(out, "%s\n", line);
+ }
+ }
+
+ if ((var = cgiGetVariable("protocol")) != NULL)
+ cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
+
+ cupsFileClose(in);
+ cupsFileClose(out);
+
+ /*
+ * 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);
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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"));
+
+ if ((var = cgiGetVariable("printer_error_policy")) != NULL)
+ attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-error-policy", NULL, var);
+
+ if ((var = cgiGetVariable("printer_op_policy")) != NULL)
+ attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-op-policy", NULL, var);
+
+ /*
+ * 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 = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML("Set Printer Options");
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML("Set Printer Options");
+
+ cgiCopyTemplateLang("printer-configured.tmpl");
+ }
+
+ cgiEndHTML();
+
+ unlink(tempfile);
+ }
+
+ unlink(filename);
+}
+
+
+/*
+ * 'do_config_server()' - Configure server settings.
+ */
+
+static void
+do_config_server(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language) /* I - Client's language */
+{
+ if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
+ {
+ /*
+ * Save basic setting changes...
+ */
+
+ http_status_t status; /* PUT status */
+ cups_file_t *cupsd; /* cupsd.conf file */
+ char tempfile[1024]; /* Temporary new cupsd.conf */
+ int tempfd; /* Temporary file descriptor */
+ cups_file_t *temp; /* Temporary file */
+ char line[1024], /* Line from cupsd.conf file */
+ *value; /* Value on line */
+ const char *server_root; /* Location of config files */
+ int linenum, /* Line number in file */
+ in_policy, /* In a policy section? */
+ in_cancel_job, /* In a cancel-job section? */
+ in_admin_location, /* In the /admin location? */
+ in_conf_location, /* In the /admin/conf location? */
+ in_root_location; /* In the / location? */
+ int remote_printers, /* Show remote printers */
+ share_printers, /* Share local printers */
+ remote_admin, /* Remote administration allowed? */
+ user_cancel_any, /* Cancel-job policy set? */
+ debug_logging; /* LogLevel debug set? */
+ int wrote_port_listen, /* Wrote the port/listen lines? */
+ wrote_browsing, /* Wrote the browsing lines? */
+ wrote_policy, /* Wrote the policy? */
+ wrote_loglevel, /* Wrote the LogLevel line? */
+ wrote_admin_location, /* Wrote the /admin location? */
+ wrote_conf_location, /* Wrote the /admin/conf location? */
+ wrote_root_location; /* Wrote the / location? */
+ int indent; /* Indentation */
+
+
+ /*
+ * Get form variables...
+ */
+
+ remote_printers = cgiGetVariable("REMOTE_PRINTERS") != NULL;
+ share_printers = cgiGetVariable("SHARE_PRINTERS") != NULL;
+ remote_admin = cgiGetVariable("REMOTE_ADMIN") != NULL;
+ user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") != NULL;
+ debug_logging = cgiGetVariable("DEBUG_LOGGING") != NULL;
+
+ /*
+ * Locate the cupsd.conf file...
+ */
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(line, sizeof(line), "%s/cupsd.conf", server_root);
+
+ /*
+ * Open the cupsd.conf file...
+ */
+
+ if ((cupsd = cupsFileOpen(line, "r")) == NULL)
+ {
+ /*
+ * Unable to open - log an error...
+ */
+
+ cgiStartHTML("Change Settings");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(line);
+ return;
+ }
+
+ /*
+ * Create a temporary file for the new cupsd.conf file...
+ */
+
+ if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ cgiStartHTML("Change Settings");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(tempfile);
+ cupsFileClose(cupsd);
+ return;
+ }
+
+ if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
+ {
+ cgiStartHTML("Change Settings");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(tempfile);
+ close(tempfd);
+ unlink(tempfile);
+ cupsFileClose(cupsd);
+ return;
+ }
+
+ /*
+ * Copy the old file to the new, making changes along the way...
+ */
+
+ in_admin_location = 0;
+ in_cancel_job = 0;
+ in_conf_location = 0;
+ in_policy = 0;
+ in_root_location = 0;
+ linenum = 0;
+ wrote_admin_location = 0;
+ wrote_browsing = 0;
+ wrote_conf_location = 0;
+ wrote_loglevel = 0;
+ wrote_policy = 0;
+ wrote_port_listen = 0;
+ wrote_root_location = 0;
+ indent = 0;
+
+ while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
+ {
+ if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen"))
+ {
+ if (!wrote_port_listen)
+ {
+ wrote_port_listen = 1;
+
+ if (share_printers || remote_admin)
+ {
+ cupsFilePuts(temp, "# Allow remote access\n");
+ cupsFilePrintf(temp, "Listen *:%d\n", ippPort());
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Only listen for connections from the local machine.\n");
+ cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
+ }
+
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ }
+ }
+ else if (!strcasecmp(line, "Browsing") ||
+ !strcasecmp(line, "BrowseAddress") ||
+ !strcasecmp(line, "BrowseAllow") ||
+ !strcasecmp(line, "BrowseDeny") ||
+ !strcasecmp(line, "BrowseOrder"))
+ {
+ if (!wrote_browsing)
+ {
+ wrote_browsing = 1;
+
+ if (remote_printers || share_printers)
+ {
+ if (remote_printers && share_printers)
+ cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
+ else if (remote_printers)
+ cupsFilePuts(temp, "# Show shared printers on the local network.\n");
+ else
+ cupsFilePuts(temp, "# Share local printers on the local network.\n");
+
+ cupsFilePuts(temp, "Browsing On\n");
+ cupsFilePuts(temp, "BrowseOrder allow,deny\n");
+
+ if (remote_printers)
+ cupsFilePuts(temp, "BrowseAllow @LOCAL\n");
+
+ if (share_printers)
+ cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
+ cupsFilePuts(temp, "Browsing Off\n");
+ }
+ }
+ }
+ else if (!strcasecmp(line, "LogLevel"))
+ {
+ wrote_loglevel = 1;
+
+ if (debug_logging)
+ {
+ cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
+ cupsFilePuts(temp, "LogLevel debug\n");
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Show general information in error_log.\n");
+ cupsFilePuts(temp, "LogLevel info\n");
+ }
+ }
+ else if (!strcasecmp(line, "\n", line, value);
+ indent += 2;
+ }
+ else if (!strcasecmp(line, ""))
+ {
+ indent -= 2;
+ if (!wrote_policy)
+ {
+ wrote_policy = 1;
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
+ " \n"
+ " Order deny,allow\n"
+ " Allow @SYSTEM\n"
+ " Allow @OWNER\n"
+ " \n");
+ }
+
+ in_policy = 0;
+
+ cupsFilePuts(temp, "\n");
+ }
+ else if (!strcasecmp(line, "\n", line, value);
+ }
+ else if (!strcasecmp(line, ""))
+ {
+ indent -= 2;
+ if (in_admin_location)
+ {
+ wrote_admin_location = 1;
+
+ if (remote_admin)
+ cupsFilePuts(temp, " # Allow remote administration...\n");
+ else
+ cupsFilePuts(temp, " # Restrict access to the admin pages...\n");
+
+ cupsFilePuts(temp, " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+ }
+ else if (in_conf_location)
+ {
+ wrote_conf_location = 1;
+
+ if (remote_admin)
+ cupsFilePuts(temp, " # Allow remote access to the configuration files...\n");
+ else
+ cupsFilePuts(temp, " # Restrict access to the configuration files...\n");
+
+ cupsFilePuts(temp, " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+ }
+ else if (in_root_location)
+ {
+ wrote_root_location = 1;
+
+ if (remote_admin && share_printers)
+ cupsFilePuts(temp, " # Allow shared printing and remote administration...\n");
+ else if (remote_admin)
+ cupsFilePuts(temp, " # Allow remote administration...\n");
+ else if (share_printers)
+ cupsFilePuts(temp, " # Allow shared printing...\n");
+ else
+ cupsFilePuts(temp, " # Restrict access to the server...\n");
+
+ cupsFilePuts(temp, " Order allow,deny\n");
+
+ if (remote_admin || share_printers)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+ }
+
+ in_admin_location = 0;
+ in_conf_location = 0;
+ in_root_location = 0;
+
+ cupsFilePuts(temp, "
\n");
+ }
+ else if (!strcasecmp(line, "\n");
+ }
+ }
+ else if (!strcasecmp(line, "") && in_cancel_job)
+ {
+ indent -= 2;
+
+ if (in_cancel_job == 1)
+ cupsFilePuts(temp, "
\n");
+
+ wrote_policy = 1;
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
+ " \n"
+ " Order deny,allow\n"
+ " Require user @OWNER @SYSTEM\n"
+ " \n");
+
+ in_cancel_job = 0;
+ }
+ else if ((in_admin_location || in_conf_location || in_root_location) &&
+ (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny") ||
+ !strcasecmp(line, "Order")))
+ continue;
+ else if (in_cancel_job == 2)
+ continue;
+ else if (!strcasecmp(line, "\n", line, value);
+ else if (line[0] == '<')
+ {
+ if (value)
+ {
+ cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
+ indent += 2;
+ }
+ else
+ {
+ if (line[1] == '/')
+ indent -= 2;
+
+ cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
+ }
+ }
+ else if (value)
+ cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
+ else
+ cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
+ }
+
+ /*
+ * Write any missing info...
+ */
+
+ if (!wrote_browsing)
+ {
+ if (remote_printers || share_printers)
+ {
+ if (remote_printers && share_printers)
+ cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
+ else if (remote_printers)
+ cupsFilePuts(temp, "# Show shared printers on the local network.\n");
+ else
+ cupsFilePuts(temp, "# Share local printers on the local network.\n");
+
+ cupsFilePuts(temp, "Browsing On\n");
+ cupsFilePuts(temp, "BrowseOrder allow,deny\n");
+
+ if (remote_printers)
+ cupsFilePuts(temp, "BrowseAllow @LOCAL\n");
+
+ if (share_printers)
+ cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
+ cupsFilePuts(temp, "Browsing Off\n");
+ }
+ }
+
+ if (!wrote_loglevel)
+ {
+ if (debug_logging)
+ {
+ cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
+ cupsFilePuts(temp, "LogLevel debug\n");
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Show general information in error_log.\n");
+ cupsFilePuts(temp, "LogLevel info\n");
+ }
+ }
+
+ if (!wrote_port_listen)
+ {
+ if (share_printers || remote_admin)
+ {
+ cupsFilePuts(temp, "# Allow remote access\n");
+ cupsFilePrintf(temp, "Listen *:%d\n", ippPort());
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Only listen for connections from the local machine.\n");
+ cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
+ }
+
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ }
+
+ if (!wrote_root_location)
+ {
+ if (remote_admin && share_printers)
+ cupsFilePuts(temp, "# Allow shared printing and remote administration...\n");
+ else if (remote_admin)
+ cupsFilePuts(temp, "# Allow remote administration...\n");
+ else if (share_printers)
+ cupsFilePuts(temp, "# Allow shared printing...\n");
+ else
+ cupsFilePuts(temp, "# Restrict access to the server...\n");
+
+ cupsFilePuts(temp, "\n"
+ " Order allow,deny\n");
+
+ if (remote_admin || share_printers)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+
+ cupsFilePuts(temp, "\n");
+ }
+
+ if (!wrote_admin_location)
+ {
+ if (remote_admin)
+ cupsFilePuts(temp, "# Allow remote administration...\n");
+ else
+ cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
+
+ cupsFilePuts(temp, "\n"
+ " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+
+ cupsFilePuts(temp, "\n");
+ }
+
+ if (!wrote_conf_location)
+ {
+ if (remote_admin)
+ cupsFilePuts(temp, "# Allow remote access to the configuration files...\n");
+ else
+ cupsFilePuts(temp, "# Restrict access to the configuration files...\n");
+
+ cupsFilePuts(temp, "\n"
+ " AuthType Basic\n"
+ " Require user @SYSTEM\n"
+ " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePuts(temp, " Allow @LOCAL\n");
+ else
+ cupsFilePuts(temp, " Allow localhost\n");
+
+ cupsFilePuts(temp, "\n");
+ }
+
+ if (!wrote_policy)
+ {
+ cupsFilePuts(temp, "\n"
+ " # Job-related operations must be done by the owner or an adminstrator...\n"
+ " \n"
+ " Require user @OWNER @SYSTEM\n"
+ " Order deny,allow\n"
+ " \n"
+ " # All administration operations require an adminstrator to authenticate...\n"
+ " \n"
+ " AuthType Basic\n"
+ " Require user @SYSTEM\n"
+ " Order deny,allow\n"
+ "\n");
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n"
+ " \n"
+ " Require user @OWNER @SYSTEM\n"
+ " Order deny,allow\n"
+ " \n");
+
+ cupsFilePuts(temp, " \n"
+ " Order deny,allow\n"
+ " \n"
+ "\n");
+ }
+
+ cupsFileClose(cupsd);
+ cupsFileClose(temp);
+
+ /*
+ * Upload the configuration file to the server...
+ */
+
+ status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
+
+ if (status != HTTP_CREATED)
+ {
+ cgiSetVariable("ERROR", httpStatus(status));
+ cgiStartHTML("Change Settings");
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ cgiSetVariable("refresh_page", "5;/admin?OP=redirect");
+
+ cgiStartHTML("Change Settings");
+ cgiCopyTemplateLang("restart.tmpl");
+ }
+
+ cgiEndHTML();
+
+ unlink(tempfile);
+ }
+ else if (cgiIsPOST())
+ {
+ /*
+ * Save hand-edited config file...
+ */
+
+ http_status_t status; /* PUT status */
+ char tempfile[1024]; /* Temporary new cupsd.conf */
+ int tempfd; /* Temporary file descriptor */
+ cups_file_t *temp; /* Temporary file */
+ const char *start, /* Start of line */
+ *end; /* End of line */
+
+
+ /*
+ * Create a temporary file for the new cupsd.conf file...
+ */
+
+ if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ cgiStartHTML("Edit Configuration File");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(tempfile);
+ return;
+ }
+
+ if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
+ {
+ cgiStartHTML("Edit Configuration File");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(tempfile);
+ close(tempfd);
+ unlink(tempfile);
+ return;
+ }
+
+ /*
+ * Copy the cupsd.conf text from the form variable...
+ */
+
+ start = cgiGetVariable("CUPSDCONF");
+ while (start)
+ {
+ if ((end = strstr(start, "\r\n")) == NULL)
+ if ((end = strstr(start, "\n")) == NULL)
+ end = start + strlen(start);
+
+ cupsFileWrite(temp, start, end - start);
+ cupsFilePutChar(temp, '\n');
+
+ if (*end == '\r')
+ start = end + 2;
+ else if (*end == '\n')
+ start = end + 1;
+ else
+ start = NULL;
+ }
+
+ cupsFileClose(temp);
+
+ /*
+ * Upload the configuration file to the server...
+ */
+
+ status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
+
+ if (status != HTTP_CREATED)
+ {
+ cgiSetVariable("ERROR", httpStatus(status));
+ cgiStartHTML("Edit Configuration File");
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ cgiSetVariable("refresh_page", "5;/admin?OP=redirect");
+
+ cgiStartHTML("Edit Configuration File");
+ cgiCopyTemplateLang("restart.tmpl");
+ }
+
+ cgiEndHTML();
+
+ unlink(tempfile);
+ }
+ else
+ {
+ struct stat info; /* cupsd.conf information */
+ cups_file_t *cupsd; /* cupsd.conf file */
+ char *buffer; /* Buffer for entire file */
+ char filename[1024]; /* Filename */
+ const char *server_root; /* Location of config files */
+
+
+ /*
+ * Locate the cupsd.conf file...
+ */
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
+
+ /*
+ * Figure out the size...
+ */
+
+ if (stat(filename, &info))
+ {
+ cgiStartHTML("Edit Configuration File");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(filename);
+ return;
+ }
+
+ if (info.st_size > (1024 * 1024))
+ {
+ cgiStartHTML("Edit Configuration File");
+ cgiSetVariable("ERROR", "Unable to edit cupsd.conf files larger than 1MB!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
+ (long)info.st_size);
+ return;
+ }
+
+ /*
+ * Open the cupsd.conf file...
+ */
+
+ if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
+ {
+ /*
+ * Unable to open - log an error...
+ */
+
+ cgiStartHTML("Edit Configuration File");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(filename);
+ return;
+ }
+
+ /*
+ * Allocate memory and load the file into a string buffer...
+ */
+
+ buffer = calloc(1, info.st_size + 1);
+
+ cupsFileRead(cupsd, buffer, info.st_size);
+ cupsFileClose(cupsd);
+
+ cgiSetVariable("CUPSDCONF", buffer);
+ free(buffer);
+
+ /*
+ * Show the current config file...
+ */
+
+ cgiStartHTML("Edit Configuration File");
+
+ printf("\n", filename);
+
+ cgiCopyTemplateLang("edit-config.tmpl");
+
+ cgiEndHTML();
+ }
+}
+
+
+/*
+ * '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)
+ {
+ cgiStartHTML("Delete Class");
+ cgiCopyTemplateLang("class-confirm.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/classes/%s", pclass);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML("Delete Class");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ 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 = cupsLastError();
+
+ cgiStartHTML("Delete Class");
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ cgiCopyTemplateLang("class-deleted.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * '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)
+ {
+ cgiStartHTML("Delete Printer");
+ cgiCopyTemplateLang("printer-confirm.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML("Delete Printer");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ 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 = cupsLastError();
+
+ cgiStartHTML("Delete Printer");
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ cgiCopyTemplateLang("printer-deleted.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_menu()' - Show the main menu...
+ */
+
+static void
+do_menu(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language) /* I - Client's language */
+{
+ cups_file_t *cupsd; /* cupsd.conf file */
+ char line[1024], /* Line from cupsd.conf file */
+ *value; /* Value on line */
+ const char *server_root; /* Location of config files */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+
+
+ /*
+ * Locate the cupsd.conf file...
+ */
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(line, sizeof(line), "%s/cupsd.conf", server_root);
+
+ cgiStartHTML("Administration");
+
+ printf("\n", line);
+
+ /*
+ * Open the cupsd.conf file...
+ */
+
+ if ((cupsd = cupsFileOpen(line, "r")) == NULL)
+ {
+ /*
+ * Unable to open - log an error...
+ */
+
+ cgiStartHTML("Administration");
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(line);
+ }
+ else
+ {
+ /*
+ * Read the file, keeping track of what settings are enabled...
+ */
+
+ int remote_access = 0, /* Remote access allowed? */
+ remote_admin = 0, /* Remote administration allowed? */
+ browsing = 1, /* Browsing enabled? */
+ browse_allow = 1, /* Browse address set? */
+ browse_address = 0, /* Browse address set? */
+ cancel_policy = 1, /* Cancel-job policy set? */
+ debug_logging = 0; /* LogLevel debug set? */
+ int linenum = 0, /* Line number in file */
+ in_policy = 0, /* In a policy section? */
+ in_cancel_job = 0, /* In a cancel-job section? */
+ in_admin_location = 0; /* In the /admin location? */
+
+
+ while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
+ {
+ if (!strcasecmp(line, "Port"))
+ {
+ remote_access = 1;
+ }
+ else if (!strcasecmp(line, "Listen"))
+ {
+ char *port; /* Pointer to port number, if any */
+
+
+ if ((port = strrchr(value, ':')) != NULL)
+ *port = '\0';
+
+ if (strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1"))
+ remote_access = 1;
+ }
+ else if (!strcasecmp(line, "Browsing"))
+ {
+ browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "true");
+ }
+ else if (!strcasecmp(line, "BrowseAddress"))
+ {
+ browse_address = 1;
+ }
+ else if (!strcasecmp(line, "BrowseAllow"))
+ {
+ browse_allow = 1;
+ }
+ else if (!strcasecmp(line, "BrowseOrder"))
+ {
+ browse_allow = !strncasecmp(value, "deny,", 5);
+ }
+ else if (!strcasecmp(line, "LogLevel"))
+ {
+ debug_logging = !strncasecmp(value, "debug", 5);
+ }
+ else if (!strcasecmp(line, ""))
+ {
+ in_policy = 0;
+ }
+ else if (!strcasecmp(line, ""))
+ {
+ in_cancel_job = 0;
+ }
+ else if (!strcasecmp(line, "Require") && in_cancel_job)
+ {
+ cancel_policy = 0;
+ }
+ else if (!strcasecmp(line, ""))
+ {
+ in_admin_location = 0;
+ }
+ else if (!strcasecmp(line, "Allow") && in_admin_location &&
+ strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1"))
+ {
+ remote_admin = 1;
+ }
+ }
+
+ cupsFileClose(cupsd);
+
+ if (browsing && browse_allow)
+ cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
+
+ if (remote_access && browsing && browse_address)
+ cgiSetVariable("SHARE_PRINTERS", "CHECKED");
+
+ if (remote_access && remote_admin)
+ cgiSetVariable("REMOTE_ADMIN", "CHECKED");
+
+ if (cancel_policy)
+ cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
+
+ if (debug_logging)
+ cgiSetVariable("DEBUG_LOGGING", "CHECKED");
+ }
+
+ /*
+ * Get the list of printers and their devices...
+ */
+
+ 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_KEYWORD,
+ "requested-attributes", NULL, "device-uri");
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
+ CUPS_PRINTER_LOCAL);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
+ CUPS_PRINTER_LOCAL);
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Got the printer list, now load the devices...
+ */
+
+ int i; /* Looping var */
+ int num_printer_devices; /* Number of devices for local printers */
+ char **printer_devices; /* Printer devices for local printers */
+
+
+ /*
+ * Count the number of printers we have...
+ */
+
+ for (num_printer_devices = 0,
+ attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
+ attr;
+ num_printer_devices ++,
+ attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI));
+
+ if (num_printer_devices > 0)
+ {
+ /*
+ * Allocate an array and copy the device strings...
+ */
+
+ printer_devices = calloc(num_printer_devices, sizeof(char *));
+
+ for (i = 0, attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
+ attr;
+ i ++, attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
+ {
+ printer_devices[i] = strdup(attr->values[0].string.text);
+ }
+
+ /*
+ * Sort the printer devices as needed...
+ */
+
+ if (num_printer_devices > 1)
+ qsort(printer_devices, num_printer_devices, sizeof(char *),
+ compare_printer_devices);
+ }
+ else
+ printer_devices = NULL;
+
+ /*
+ * Free the printer list and get the device list...
+ */
+
+ ippDelete(response);
+
+ 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);
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Got the device list, let's parse it...
+ */
+
+ const char *device_uri, /* device-uri attribute value */
+ *device_make_and_model, /* device-make-and-model value */
+ *device_info; /* device-info value */
+
+
+ for (i = 0, attr = response->attrs; attr; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a device...
+ */
+
+ while (attr && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ /*
+ * Pull the needed attributes from this device...
+ */
+
+ device_info = NULL;
+ device_make_and_model = NULL;
+ device_uri = NULL;
+
+ while (attr && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "device-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_info = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-make-and-model") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_make_and_model = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-uri") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ device_uri = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (device_info && device_make_and_model && device_uri &&
+ strcasecmp(device_make_and_model, "unknown") &&
+ strchr(device_uri, ':'))
+ {
+ /*
+ * Yes, now see if there is already a printer for this
+ * device...
+ */
+
+ if (!bsearch(&device_uri, printer_devices, num_printer_devices,
+ sizeof(char *), compare_printer_devices))
+ {
+ /*
+ * Not found, so it must be a new printer...
+ */
+
+ char options[1024], /* Form variables for this device */
+ *options_ptr; /* Pointer into string */
+ const char *ptr; /* Pointer into device string */
+
+
+ /*
+ * Format the printer name variable for this device...
+ *
+ * We use the device-info string first, then device-uri,
+ * and finally device-make-and-model to come up with a
+ * suitable name.
+ */
+
+ strcpy(options, "PRINTER_NAME=");
+ options_ptr = options + strlen(options);
+
+ if (strncasecmp(device_info, "unknown", 7))
+ ptr = device_info;
+ else if ((ptr = strstr(device_uri, "://")) != NULL)
+ ptr += 3;
+ else
+ ptr = device_make_and_model;
+
+ for (;
+ options_ptr < (options + sizeof(options) - 1) && *ptr;
+ ptr ++)
+ if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.')
+ *options_ptr++ = *ptr;
+ else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_')
+ *options_ptr++ = '_';
+ else if (*ptr == '?' || *ptr == '(')
+ break;
+
+ /*
+ * Then add the make and model in the printer info, so
+ * that MacOS clients see something reasonable...
+ */
+
+ strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer"
+ "&PRINTER_INFO=",
+ sizeof(options) - (options_ptr - options));
+ options_ptr += strlen(options_ptr);
+
+ cgiFormEncode(options_ptr, device_make_and_model,
+ sizeof(options) - (options_ptr - options));
+ options_ptr += strlen(options_ptr);
+
+ /*
+ * Then copy the device URI...
+ */
+
+ strlcpy(options_ptr, "&DEVICE_URI=",
+ sizeof(options) - (options_ptr - options));
+ options_ptr += strlen(options_ptr);
+
+ cgiFormEncode(options_ptr, device_uri,
+ sizeof(options) - (options_ptr - options));
+ options_ptr += strlen(options_ptr);
+
+ if (options_ptr < (options + sizeof(options) - 1))
+ {
+ *options_ptr++ = '|';
+ cgiFormEncode(options_ptr, device_make_and_model,
+ sizeof(options) - (options_ptr - options));
+ }
+
+ /*
+ * Finally, set the form variables for this printer...
+ */
+
+ cgiSetArray("device_info", i, device_info);
+ cgiSetArray("device_make_and_model", i, device_make_and_model);
+ cgiSetArray("device_options", i, options);
+ cgiSetArray("device_uri", i, device_uri);
+ i ++;
+ }
+ }
+
+ if (!attr)
+ break;
+ }
+
+ /*
+ * Free the device list...
+ */
+
+ ippDelete(response);
+
+ if (num_printer_devices)
+ free(printer_devices);
+ }
+ }
+
+ /*
+ * Finally, show the main menu template...
+ */
+
+ cgiCopyTemplateLang("admin.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * '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 */
+ const char *title) /* I - Title of page */
+{
+ 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)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ 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 = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ if (op == IPP_PAUSE_PRINTER)
+ cgiCopyTemplateLang("printer-stop.tmpl");
+ else if (op == IPP_RESUME_PRINTER)
+ cgiCopyTemplateLang("printer-start.tmpl");
+ else if (op == CUPS_ACCEPT_JOBS)
+ cgiCopyTemplateLang("printer-accept.tmpl");
+ else if (op == CUPS_REJECT_JOBS)
+ cgiCopyTemplateLang("printer-reject.tmpl");
+ else if (op == IPP_PURGE_JOBS)
+ cgiCopyTemplateLang("printer-purge.tmpl");
+ else if (op == CUPS_SET_DEFAULT)
+ cgiCopyTemplateLang("printer-default.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
+ */
+
+static void
+do_set_allowed_users(
+ http_t *http, /* I - HTTP connection */
+ cups_lang_t *language) /* I - Language */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ const char *printer, /* Printer name (purge-jobs) */
+ *users, /* List of users or groups */
+ *type; /* Allow/deny type */
+ int num_users; /* Number of users */
+ char *ptr, /* Pointer into users string */
+ *end, /* Pointer to end of users string */
+ quote; /* Quote character */
+ ipp_attribute_t *attr; /* Attribute */
+ ipp_status_t status; /* Operation status... */
+ static const char * const attrs[] = /* Requested attributes */
+ {
+ "requesting-user-name-allowed",
+ "requesting-user-name-denied"
+ };
+
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML("Set Allowed Users");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ users = cgiGetVariable("users");
+ type = cgiGetVariable("type");
+
+ if (!users || !type ||
+ (strcmp(type, "requesting-user-name-allowed") &&
+ strcmp(type, "requesting-user-name-denied")))
+ {
+ /*
+ * Build a 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;
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ status = response->request.status.status_code;
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ cgiStartHTML("Set Allowed Users");
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ cgiCopyTemplateLang("users.tmpl");
+
+ cgiEndHTML();
+ }
+ else
+ {
+ /*
+ * Save the changes...
+ */
+
+ for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
+ {
+ /*
+ * Skip whitespace and commas...
+ */
+
+ while (*ptr == ',' || isspace(*ptr & 255))
+ ptr ++;
+
+ if (*ptr == '\'' || *ptr == '\"')
+ {
+ /*
+ * Scan quoted name...
+ */
+
+ quote = *ptr++;
+
+ for (end = ptr; *end; end ++)
+ if (*end == quote)
+ break;
+ }
+ else
+ {
+ /*
+ * Scan space or comma-delimited name...
+ */
+
+ for (end = ptr; *end; end ++)
+ if (isspace(*end & 255) || *end == ',')
+ break;
+ }
+
+ /*
+ * Advance to the next name...
+ */
+
+ ptr = end;
+ }
+
+ /*
+ * Build a CUPS-Add-Printer request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name-{allowed,denied}
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ if (num_users == 0)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name-allowed", NULL, "all");
+ else
+ {
+ attr = ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ type, num_users, NULL, NULL);
+
+ for (i = 0, ptr = (char *)users; *ptr; i ++)
+ {
+ /*
+ * Skip whitespace and commas...
+ */
+
+ while (*ptr == ',' || isspace(*ptr & 255))
+ ptr ++;
+
+ if (*ptr == '\'' || *ptr == '\"')
+ {
+ /*
+ * Scan quoted name...
+ */
+
+ quote = *ptr++;
+
+ for (end = ptr; *end; end ++)
+ if (*end == quote)
+ break;
+ }
+ else
+ {
+ /*
+ * Scan space or comma-delimited name...
+ */
+
+ for (end = ptr; *end; end ++)
+ if (isspace(*end & 255) || *end == ',')
+ break;
+ }
+
+ /*
+ * Terminate the name...
+ */
+
+ if (*end)
+ *end++ = '\0';
+
+ /*
+ * Add the name...
+ */
+
+ attr->values[i].string.text = strdup(ptr);
+
+ /*
+ * Advance to the next name...
+ */
+
+ ptr = end;
+ }
+ }
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ status = response->request.status.status_code;
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML("Set Allowed Users");
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML("Set Allowed Users");
+
+ cgiCopyTemplateLang("printer-modified.tmpl");
+ }
+
+ cgiEndHTML();
+ }
+}
+
+
+/*
+ * 'do_set_sharing()' - Set printer-is-shared value...
+ */
+
+static void
+do_set_sharing(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language) /* I - Language */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ const char *printer, /* Printer name */
+ *shared; /* Sharing value */
+ ipp_status_t status; /* Operation status... */
+
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiStartHTML("Set Publishing");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if ((shared = cgiGetVariable("SHARED")) == NULL)
+ {
+ cgiSetVariable("ERROR", "Missing SHARED parameter");
+ cgiStartHTML("Set Publishing");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Build a CUPS-Add-Printer request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * printer-is-shared
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ status = response->request.status.status_code;
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML("Set Publishing");
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML("Set Publishing");
+
+ cgiCopyTemplateLang("printer-modified.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'match_string()' - Return the number of matching characters.
+ */
+
+static int /* O - Number of matching characters */
+match_string(const char *a, /* I - First string */
+ const char *b) /* I - Second string */
+{
+ int count; /* Number of matching characters */
+
+
+ /*
+ * Loop through both strings until we hit the end of either or we find
+ * a non-matching character. For the purposes of comparison, we ignore
+ * whitespace and do a case-insensitive comparison so that we have a
+ * better chance of finding a match...
+ */
+
+ for (count = 0; *a && *b; a++, b++, count ++)
+ {
+ /*
+ * Skip leading whitespace characters...
+ */
+
+ while (isspace(*a & 255))
+ a ++;
+
+ while (isspace(*b & 255))
+ b ++;
+
+ /*
+ * Break out if we run out of characters...
+ */
+
+ if (!*a || !*b)
+ break;
+
+ /*
+ * Do a case-insensitive comparison of the next two chars...
+ */
+
+ if (tolower(*a & 255) != tolower(*b & 255))
+ break;
+ }
+
+ return (count);
+}
+
+
+/*
+ * End of "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/cgi-private.h b/cgi-bin/cgi-private.h
new file mode 100644
index 000000000..b2af6d715
--- /dev/null
+++ b/cgi-bin/cgi-private.h
@@ -0,0 +1,44 @@
+/*
+ * "$Id: cgi-private.h 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Private CGI definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+#include
+#include
+#include
+
+
+/*
+ * Limits...
+ */
+
+#define CUPS_PAGE_MAX 10 /* Maximum items per page */
+
+
+/*
+ * End of "$Id: cgi-private.h 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h
new file mode 100644
index 000000000..ac63c4546
--- /dev/null
+++ b/cgi-bin/cgi.h
@@ -0,0 +1,106 @@
+/*
+ * "$Id: cgi.h 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * CGI support library definitions.
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+#ifndef _CUPS_CGI_H_
+# define _CUPS_CGI_H_
+
+# include
+# include
+# include
+# include
+
+# ifdef WIN32
+# include
+# include
+# else
+# include
+# endif /* WIN32 */
+
+# include
+# include
+# include "help-index.h"
+
+
+/*
+ * Types...
+ */
+
+typedef struct cgi_file_s /**** Uploaded file data ****/
+{
+ char tempfile[1024], /* Temporary file containing data */
+ *name, /* Variable name */
+ *filename, /* Original filename */
+ *mimetype; /* MIME media type */
+ size_t filesize; /* Size of uploaded file */
+} cgi_file_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cgiAbort(const char *title, const char *stylesheet,
+ const char *format, ...);
+extern int cgiCheckVariables(const char *names);
+extern void *cgiCompileSearch(const char *query);
+extern void cgiCopyTemplateFile(FILE *out, const char *tmpl);
+extern void cgiCopyTemplateLang(const char *tmpl);
+extern int cgiDoSearch(void *search, const char *text);
+extern void cgiEndHTML(void);
+extern char *cgiFormEncode(char *dst, const char *src, size_t dstsize);
+extern void cgiFreeSearch(void *search);
+extern const char *cgiGetArray(const char *name, int element);
+extern void cgiGetAttributes(ipp_t *request, const char *tmpl);
+extern char *cgiGetCookie(const char *name, char *buf, int buflen);
+extern const cgi_file_t *cgiGetFile(void);
+extern cups_array_t *cgiGetIPPObjects(ipp_t *response, void *search);
+extern int cgiGetSize(const char *name);
+extern char *cgiGetTemplateDir(void);
+extern const char *cgiGetVariable(const char *name);
+extern int cgiInitialize(void);
+extern int cgiIsPOST(void);
+extern char *cgiRewriteURL(const char *uri, char *url, int urlsize,
+ const char *newresource);
+extern void cgiSetArray(const char *name, int element,
+ const char *value);
+extern void cgiSetCookie(const char *name, const char *value,
+ const char *path, const char *domain,
+ time_t expires, int secure);
+extern ipp_attribute_t *cgiSetIPPObjectVars(ipp_attribute_t *obj,
+ const char *prefix, int element);
+extern int cgiSetIPPVars(ipp_t *response, const char *filter_name,
+ const char *filter_value,
+ const char *prefix, int parent_el);
+extern void cgiSetServerVersion(void);
+extern void cgiSetSize(const char *name, int size);
+extern void cgiSetVariable(const char *name, const char *value);
+extern void cgiShowJobs(http_t *http, const char *dest);
+extern void cgiStartHTML(const char *title);
+
+
+#endif /* !_CUPS_CGI_H_ */
+
+/*
+ * End of "$Id: cgi.h 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c
new file mode 100644
index 000000000..52c12efab
--- /dev/null
+++ b/cgi-bin/classes.c
@@ -0,0 +1,396 @@
+/*
+ * "$Id: classes.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Class status CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.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 */
+ static const char *def_attrs[] = /* Attributes for default printer */
+ {
+ "printer-name",
+ "printer-uri-supported"
+ };
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+ op = cgiGetVariable("OP");
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "classes");
+
+ /*
+ * Get the request language...
+ */
+
+ language = cupsLangDefault();
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Tell the client to expect UTF-8 encoded HTML...
+ */
+
+ puts("Content-Type: text/html;charset=utf-8\n");
+
+ /*
+ * See if we need to show a list of printers or the status of a
+ * single printer...
+ */
+
+ cgiSetServerVersion();
+
+ pclass = argv[0];
+ if (strcmp(pclass, "/") == 0 || strcmp(pclass, "classes.cgi") == 0)
+ {
+ pclass = NULL;
+ cgiSetVariable("TITLE", _cupsLangString(language, _("Class")));
+ }
+ else
+ cgiSetVariable("TITLE", pclass);
+
+ if (op == NULL || strcasecmp(op, "print-test-page") != 0)
+ {
+ /*
+ * Show the standard header...
+ */
+
+ cgiCopyTemplateLang("header.tmpl");
+
+ /*
+ * 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs);
+
+ 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 url[HTTP_MAX_URI]; /* New URL */
+
+
+ cgiSetVariable("DEFAULT_URI",
+ cgiRewriteURL(attr->values[0].string.text,
+ url, sizeof(url), NULL));
+ }
+
+ 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;
+
+ if (getenv("REMOTE_USER") != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, getenv("REMOTE_USER"));
+ }
+ 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;
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/classes/%s", pclass);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+ }
+
+ cgiGetAttributes(request, "classes.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+ }
+
+ /*
+ * Write the report...
+ */
+
+ cgiCopyTemplateLang("classes.tmpl");
+
+ /*
+ * 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;
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/classes/%s", 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);
+
+ if (getenv("REMOTE_USER") != NULL)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, getenv("REMOTE_USER"));
+
+ if (strcmp(getenv("REMOTE_USER"), "root"))
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, "unknown");
+
+ cgiGetAttributes(request, "jobs.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+
+ cgiCopyTemplateLang("jobs.tmpl");
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Print a test page...
+ */
+
+ char filename[1024]; /* Test page filename */
+ const char *datadir; /* CUPS_DATADIR env var */
+ char refresh[1024]; /* Refresh URL */
+
+
+ cgiFormEncode(uri, pclass, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "2;/classes/%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir);
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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,
+ filename)) != NULL)
+ {
+ status = response->request.status.status_code;
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ cgiSetVariable("PRINTER_NAME", pclass);
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiCopyTemplateLang("header.tmpl");
+
+ /*
+ * Show the result...
+ */
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ cgiCopyTemplateLang("test-page.tmpl");
+ }
+
+ cgiCopyTemplateLang("trailer.tmpl");
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+ cupsLangFree(language);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: classes.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/help-index.c b/cgi-bin/help-index.c
new file mode 100644
index 000000000..0b2e53b09
--- /dev/null
+++ b/cgi-bin/help-index.c
@@ -0,0 +1,1103 @@
+/*
+ * "$Id: help-index.c 4863 2005-12-03 04:28:10Z mike $"
+ *
+ * On-line help index routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * helpDeleteIndex() - Delete an index, freeing all memory used.
+ * helpFindNode() - Find a node in an index.
+ * helpLoadIndex() - Load a help index from disk.
+ * helpSaveIndex() - Save a help index to disk.
+ * helpSearchIndex() - Search an index.
+ * help_compile_search() - Convert a search string into a regular expression.
+ * help_create_sorted() - Create the sorted node array.
+ * help_delete_node() - Free all memory used by a node.
+ * help_insert_node() - Insert a node in an index.
+ * help_load_directory() - Load a directory of files into an index.
+ * help_load_file() - Load a HTML files into an index.
+ * help_new_node() - Create a new node and add it to an index.
+ * help_sort_nodes_by_name() - Sort nodes by section, filename, and anchor.
+ * help_sort_nodes_by_score() - Sort nodes by score and text.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+#include
+
+
+/*
+ * Local functions...
+ */
+
+static void help_create_sorted(help_index_t *hi);
+static void help_delete_node(help_node_t *n);
+static void help_insert_node(help_index_t *hi, help_node_t *n);
+static int help_load_directory(help_index_t *hi,
+ const char *directory,
+ const char *relative);
+static int help_load_file(help_index_t *hi,
+ const char *filename,
+ const char *relative,
+ time_t mtime);
+static help_node_t *help_new_node(const char *filename, const char *anchor,
+ const char *section, const char *text,
+ time_t mtime, off_t offset,
+ size_t length);
+static int help_sort_by_name(const void *p1, const void *p2);
+static int help_sort_by_score(const void *p1, const void *p2);
+
+
+/*
+ * 'helpDeleteIndex()' - Delete an index, freeing all memory used.
+ */
+
+void
+helpDeleteIndex(help_index_t *hi)
+{
+ int i; /* Looping var */
+
+
+ DEBUG_printf(("helpDeleteIndex(hi=%p)\n", hi));
+
+ if (!hi)
+ return;
+
+ if (!hi->search)
+ {
+ for (i = 0; i < hi->num_nodes; i ++)
+ help_delete_node(hi->nodes[i]);
+ }
+
+ free(hi->nodes);
+
+ if (hi->sorted)
+ free(hi->sorted);
+
+ free(hi);
+}
+
+
+/*
+ * 'helpFindNode()' - Find a node in an index.
+ */
+
+help_node_t ** /* O - Node pointer or NULL */
+helpFindNode(help_index_t *hi, /* I - Index */
+ const char *filename, /* I - Filename */
+ const char *anchor) /* I - Anchor */
+{
+ help_node_t key, /* Search key */
+ *ptr; /* Pointer to key */
+
+
+ DEBUG_printf(("helpFindNode(hi=%p, filename=\"%s\", anchor=\"%s\")\n",
+ hi, filename ? filename : "(nil)", anchor ? anchor : "(nil)"));
+
+ /*
+ * Range check input...
+ */
+
+ if (!hi || !filename)
+ return (NULL);
+
+ /*
+ * Initialize the search key...
+ */
+
+ key.filename = (char *)filename;
+ key.anchor = (char *)anchor;
+ ptr = &key;
+
+ /*
+ * Return any match...
+ */
+
+ return ((help_node_t **)bsearch(&ptr, hi->nodes, hi->num_nodes,
+ sizeof(help_node_t *), help_sort_by_name));
+}
+
+
+/*
+ * 'helpLoadIndex()' - Load a help index from disk.
+ */
+
+help_index_t * /* O - Index pointer or NULL */
+helpLoadIndex(const char *hifile, /* I - Index filename */
+ const char *directory) /* I - Directory that is indexed */
+{
+ help_index_t *hi; /* Help index */
+ cups_file_t *fp; /* Current file */
+ char line[2048], /* Line from file */
+ *ptr, /* Pointer into line */
+ *filename, /* Filename in line */
+ *anchor, /* Anchor in line */
+ *sectptr, /* Section pointer in line */
+ section[1024], /* Section name */
+ *text; /* Text in line */
+ time_t mtime; /* Modification time */
+ off_t offset; /* Offset into file */
+ size_t length; /* Length in bytes */
+ int update; /* Update? */
+ int i; /* Looping var */
+ help_node_t *node; /* Current node */
+
+
+ DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")\n",
+ hifile, directory));
+
+ /*
+ * Create a new, empty index.
+ */
+
+ hi = (help_index_t *)calloc(1, sizeof(help_index_t));
+
+ /*
+ * Try loading the existing index file...
+ */
+
+ if ((fp = cupsFileOpen(hifile, "r")) != NULL)
+ {
+ /*
+ * Lock the file and then read the first line...
+ */
+
+ cupsFileLock(fp, 1);
+
+ if (cupsFileGets(fp, line, sizeof(line)) && !strcmp(line, "HELPV1"))
+ {
+ /*
+ * Got a valid header line, now read the data lines...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ /*
+ * Each line looks like one of the following:
+ *
+ * filename mtime offset length "section" "text"
+ * filename#anchor offset length "text"
+ */
+
+ filename = line;
+
+ if ((ptr = strchr(line, ' ')) == NULL)
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ if ((anchor = strrchr(filename, '#')) != NULL)
+ {
+ *anchor++ = '\0';
+ mtime = 0;
+ }
+ else
+ mtime = strtol(ptr, &ptr, 10);
+
+ offset = strtoll(ptr, &ptr, 10);
+ length = strtoll(ptr, &ptr, 10);
+
+ while (isspace(*ptr & 255))
+ ptr ++;
+
+ if (!anchor)
+ {
+ /*
+ * Get section...
+ */
+
+ if (*ptr != '\"')
+ break;
+
+ ptr ++;
+ sectptr = ptr;
+
+ while (*ptr && *ptr != '\"')
+ ptr ++;
+
+ if (*ptr != '\"')
+ break;
+
+ *ptr++ = '\0';
+
+ strlcpy(section, sectptr, sizeof(section));
+
+ while (isspace(*ptr & 255))
+ ptr ++;
+ }
+
+ if (*ptr != '\"')
+ break;
+
+ ptr ++;
+ text = ptr;
+
+ while (*ptr && *ptr != '\"')
+ ptr ++;
+
+ if (*ptr != '\"')
+ break;
+
+ *ptr++ = '\0';
+
+ if ((node = help_new_node(filename, anchor, section, text,
+ mtime, offset, length)) == NULL)
+ break;
+
+ help_insert_node(hi, node);
+
+ node->score = -1;
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+
+ /*
+ * Scan for new/updated files...
+ */
+
+ update = help_load_directory(hi, directory, NULL);
+
+ /*
+ * Remove any files that are no longer installed...
+ */
+
+ for (i = 0; i < hi->num_nodes;)
+ {
+ if (hi->nodes[i]->score < 0)
+ {
+ /*
+ * Delete this node...
+ */
+
+ help_delete_node(hi->nodes[i]);
+
+ hi->num_nodes --;
+ if (i < hi->num_nodes)
+ memmove(hi->nodes + i, hi->nodes + i + 1,
+ (hi->num_nodes - i) * sizeof(help_node_t *));
+
+ update = 1;
+ }
+ else
+ {
+ /*
+ * Keep this node...
+ */
+
+ i ++;
+ }
+ }
+
+ /*
+ * Save the index if we updated it...
+ */
+
+ if (update)
+ helpSaveIndex(hi, hifile);
+
+ /*
+ * Create the sorted array...
+ */
+
+ help_create_sorted(hi);
+
+ /*
+ * Return the index...
+ */
+
+ return (hi);
+}
+
+
+/*
+ * 'helpSaveIndex()' - Save a help index to disk.
+ */
+
+int /* O - 0 on success, -1 on error */
+helpSaveIndex(help_index_t *hi, /* I - Index */
+ const char *hifile) /* I - Index filename */
+{
+ cups_file_t *fp; /* Index file */
+ int i; /* Looping var */
+ help_node_t *node; /* Current node */
+
+
+ DEBUG_printf(("helpSaveIndex(hi=%p, hifile=\"%s\")\n", hi, hifile));
+
+ /*
+ * Try creating a new index file...
+ */
+
+ if ((fp = cupsFileOpen(hifile, "w9")) == NULL)
+ return (-1);
+
+ /*
+ * Lock the file while we write it...
+ */
+
+ cupsFileLock(fp, 1);
+
+ cupsFilePuts(fp, "HELPV1\n");
+
+ for (i = 0; i < hi->num_nodes; i ++)
+ {
+ /*
+ * Write the current node with/without the anchor...
+ */
+
+ node = hi->nodes[i];
+
+ if (node->anchor)
+ {
+ if (cupsFilePrintf(fp, "%s#%s " CUPS_LLFMT " " CUPS_LLFMT " \"%s\"\n",
+ node->filename, node->anchor,
+ CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
+ node->text) < 0)
+ break;
+ }
+ else
+ {
+ if (cupsFilePrintf(fp, "%s %d " CUPS_LLFMT " " CUPS_LLFMT " \"%s\" \"%s\"\n",
+ node->filename, node->mtime,
+ CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
+ node->section ? node->section : "", node->text) < 0)
+ break;
+ }
+ }
+
+ if (cupsFileClose(fp) < 0)
+ return (-1);
+ else if (i < hi->num_nodes)
+ return (-1);
+ else
+ return (0);
+}
+
+
+/*
+ * 'helpSearchIndex()' - Search an index.
+ */
+
+help_index_t * /* O - Search index */
+helpSearchIndex(help_index_t *hi, /* I - Index */
+ const char *query, /* I - Query string */
+ const char *section, /* I - Limit search to this section */
+ const char *filename) /* I - Limit search to this file */
+{
+ int i; /* Looping var */
+ help_index_t *search; /* Search index */
+ help_node_t **n; /* Current node */
+ void *sc; /* Search context */
+ int matches; /* Number of matches */
+
+
+ DEBUG_printf(("helpSearchIndex(hi=%p, query=\"%s\", filename=\"%s\")\n",
+ hi, query ? query : "(nil)",
+ filename ? filename : "(nil)"));
+
+ /*
+ * Range check...
+ */
+
+ if (!hi || !query)
+ return (NULL);
+
+ for (i = 0, n = hi->nodes; i < hi->num_nodes; i ++, n ++)
+ n[0]->score = 0;
+
+ if (filename)
+ {
+ n = helpFindNode(hi, filename, NULL);
+ if (!n)
+ return (NULL);
+ }
+ else
+ n = hi->nodes;
+
+ /*
+ * Convert the query into a regular expression...
+ */
+
+ sc = cgiCompileSearch(query);
+ if (!sc)
+ return (NULL);
+
+ /*
+ * Allocate a search index...
+ */
+
+ search = calloc(1, sizeof(help_index_t));
+ if (!search)
+ {
+ cgiFreeSearch(sc);
+ return (NULL);
+ }
+
+ search->search = 1;
+
+ /*
+ * Check each node in the index, adding matching nodes to the
+ * search index...
+ */
+
+ for (i = n - hi->nodes; i < hi->num_nodes; i ++, n ++)
+ if (section && strcmp(n[0]->section, section))
+ continue;
+ else if (filename && strcmp(n[0]->filename, filename))
+ continue;
+ else if ((matches = cgiDoSearch(sc, n[0]->text)) > 0)
+ {
+ /*
+ * Found a match, add the node to the search index...
+ */
+
+ help_insert_node(search, *n);
+
+ n[0]->score = matches;
+ }
+
+ /*
+ * Free the search context...
+ */
+
+ cgiFreeSearch(sc);
+
+ /*
+ * Sort the results...
+ */
+
+ help_create_sorted(search);
+
+ /*
+ * Return the results...
+ */
+
+ return (search);
+}
+
+
+/*
+ * 'help_create_sorted()' - Create the sorted node array.
+ */
+
+static void
+help_create_sorted(help_index_t *hi) /* I - Index */
+{
+ DEBUG_printf(("help_create_sorted(hi=%p)\n", hi));
+
+ /*
+ * Free any existing sorted array...
+ */
+
+ if (hi->sorted)
+ free(hi->sorted);
+
+ /*
+ * Create a new sorted array...
+ */
+
+ hi->sorted = calloc(hi->num_nodes, sizeof(help_node_t *));
+
+ if (!hi->sorted)
+ return;
+
+ /*
+ * Copy the nodes to the new array...
+ */
+
+ memcpy(hi->sorted, hi->nodes, hi->num_nodes * sizeof(help_node_t *));
+
+ /*
+ * Sort the new array by score and text.
+ */
+
+ if (hi->num_nodes > 1)
+ qsort(hi->sorted, hi->num_nodes, sizeof(help_node_t *),
+ help_sort_by_score);
+}
+
+
+/*
+ * 'help_delete_node()' - Free all memory used by a node.
+ */
+
+static void
+help_delete_node(help_node_t *n) /* I - Node */
+{
+ DEBUG_printf(("help_delete_node(n=%p)\n", n));
+
+ if (!n)
+ return;
+
+ if (n->filename)
+ free(n->filename);
+
+ if (n->anchor)
+ free(n->anchor);
+
+ if (n->section)
+ free(n->section);
+
+ if (n->text)
+ free(n->text);
+
+ free(n);
+}
+
+
+/*
+ * 'help_insert_node()' - Insert a node in an index.
+ */
+
+static void
+help_insert_node(help_index_t *hi, /* I - Index */
+ help_node_t *n) /* I - Node */
+{
+ int current, /* Current node */
+ left, /* Left side */
+ right, /* Right side */
+ diff; /* Difference between nodes */
+ help_node_t **temp; /* Temporary node pointer */
+
+
+ DEBUG_printf(("help_insert_node(hi=%p, n=%p)\n", hi, n));
+
+ /*
+ * Allocate memory as needed...
+ */
+
+ if (hi->num_nodes >= hi->alloc_nodes)
+ {
+ /*
+ * Expand the array in 128 node increments...
+ */
+
+ hi->alloc_nodes += 128;
+ if (hi->alloc_nodes == 128)
+ temp = (help_node_t **)malloc(hi->alloc_nodes * sizeof(help_node_t *));
+ else
+ temp = (help_node_t **)realloc(hi->nodes,
+ hi->alloc_nodes * sizeof(help_node_t *));
+
+ if (!temp)
+ return;
+
+ hi->nodes = temp;
+ }
+
+ /*
+ * Find the insertion point...
+ */
+
+ if (hi->num_nodes == 0 ||
+ help_sort_by_name(&n, hi->nodes + hi->num_nodes - 1) > 0)
+ {
+ /*
+ * Last node...
+ */
+
+ hi->nodes[hi->num_nodes] = n;
+ hi->num_nodes ++;
+ return;
+ }
+ else if (help_sort_by_name(&n, hi->nodes) < 0)
+ {
+ /*
+ * First node...
+ */
+
+ memmove(hi->nodes + 1, hi->nodes, hi->num_nodes * sizeof(help_node_t *));
+ hi->nodes[0] = n;
+ hi->num_nodes ++;
+ return;
+ }
+
+ /*
+ * Otherwise, do a binary insertion...
+ */
+
+ left = 0;
+ right = hi->num_nodes - 1;
+
+ do
+ {
+ current = (left + right) / 2;
+ diff = help_sort_by_name(&n, hi->nodes + current);
+
+ if (!diff)
+ break;
+ else if (diff < 0)
+ right = current;
+ else
+ left = current;
+ }
+ while ((right - left) > 1);
+
+ if (diff > 0)
+ current ++;
+
+ memmove(hi->nodes + current + 1, hi->nodes + current,
+ (hi->num_nodes - current) * sizeof(help_node_t *));
+ hi->nodes[current] = n;
+ hi->num_nodes ++;
+}
+
+
+/*
+ * 'help_load_directory()' - Load a directory of files into an index.
+ */
+
+static int /* O - 0 = success, -1 = error, 1 = updated */
+help_load_directory(
+ help_index_t *hi, /* I - Index */
+ const char *directory, /* I - Directory */
+ const char *relative) /* I - Relative path */
+{
+ int i; /* Looping var */
+ cups_dir_t *dir; /* Directory file */
+ cups_dentry_t *dent; /* Directory entry */
+ char *ext, /* Pointer to extension */
+ filename[1024], /* Full filename */
+ relname[1024]; /* Relative filename */
+ int update; /* Updated? */
+ help_node_t **node; /* Current node */
+
+
+ DEBUG_printf(("help_load_directory(hi=%p, directory=\"%s\", relative=\"%s\")\n",
+ hi, directory ? directory : "(nil)", relative ? relative : "(nil)"));
+
+ /*
+ * Open the directory and scan it...
+ */
+
+ if ((dir = cupsDirOpen(directory)) == NULL)
+ return (0);
+
+ update = 0;
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ /*
+ * Get absolute and relative filenames...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", directory, dent->filename);
+ if (relative)
+ snprintf(relname, sizeof(relname), "%s/%s", relative, dent->filename);
+ else
+ strlcpy(relname, dent->filename, sizeof(relname));
+
+ /*
+ * Check if we have a HTML file...
+ */
+
+ if ((ext = strstr(dent->filename, ".html")) != NULL &&
+ (!ext[5] || !strcmp(ext + 5, ".gz")))
+ {
+ /*
+ * HTML file, see if we have already indexed the file...
+ */
+
+ if ((node = helpFindNode(hi, relname, NULL)) != NULL)
+ {
+ /*
+ * File already indexed - check dates to confirm that the
+ * index is up-to-date...
+ */
+
+ if (node[0]->mtime == dent->fileinfo.st_mtime)
+ {
+ /*
+ * Same modification time, so mark all of the nodes
+ * for this file as up-to-date...
+ */
+
+ for (i = node - hi->nodes; i < hi->num_nodes; i ++, node ++)
+ if (!strcmp(node[0]->filename, relname))
+ node[0]->score = 0;
+ else
+ break;
+
+ continue;
+ }
+ }
+
+ update = 1;
+
+ help_load_file(hi, filename, relname, dent->fileinfo.st_mtime);
+ }
+ else if (S_ISDIR(dent->fileinfo.st_mode))
+ {
+ /*
+ * Process sub-directory...
+ */
+
+ if (help_load_directory(hi, filename, relname) == 1)
+ update = 1;
+ }
+ }
+
+ cupsDirClose(dir);
+
+ return (update);
+}
+
+
+/*
+ * 'help_load_file()' - Load a HTML files into an index.
+ */
+
+static int /* O - 0 = success, -1 = error */
+help_load_file(
+ help_index_t *hi, /* I - Index */
+ const char *filename, /* I - Filename */
+ const char *relative, /* I - Relative path */
+ time_t mtime) /* I - Modification time */
+{
+ cups_file_t *fp; /* HTML file */
+ help_node_t *node, /* Current node */
+ **n; /* Node pointer */
+ char line[1024], /* Line from file */
+ section[1024], /* Section */
+ *ptr, /* Pointer into line */
+ *anchor, /* Anchor name */
+ *text; /* Text for anchor */
+ off_t offset; /* File offset */
+ char quote; /* Quote character */
+
+
+ DEBUG_printf(("help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", mtime=%ld)\n",
+ hi, filename ? filename : "(nil)",
+ relative ? relative : "(nil)", mtime));
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ return (-1);
+
+ node = NULL;
+ offset = 0;
+
+ strcpy(section, "Other");
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ /*
+ * Look for "", "")) != NULL)
+ {
+ /*
+ * Strip comment stuff from end of line...
+ */
+
+ for (*ptr-- = '\0'; ptr > line && isspace(*ptr & 255); *ptr-- = '\0');
+
+ if (isspace(*ptr & 255))
+ *ptr = '\0';
+ }
+ continue;
+ }
+
+ for (ptr = line; (ptr = strchr(ptr, '<')) != NULL;)
+ {
+ ptr ++;
+
+ if (!strncasecmp(ptr, "TITLE>", 6))
+ {
+ /*
+ * Found the title...
+ */
+
+ anchor = NULL;
+ ptr += 6;
+ }
+ else if (!strncasecmp(ptr, "A NAME=", 7))
+ {
+ /*
+ * Found an anchor...
+ */
+
+ ptr += 7;
+
+ if (*ptr == '\"' || *ptr == '\'')
+ {
+ /*
+ * Get quoted anchor...
+ */
+
+ quote = *ptr;
+ anchor = ptr + 1;
+ if ((ptr = strchr(anchor, quote)) != NULL)
+ *ptr++ = '\0';
+ else
+ break;
+ }
+ else
+ {
+ /*
+ * Get unquoted anchor...
+ */
+
+ anchor = ptr + 1;
+
+ for (ptr = anchor; *ptr && *ptr != '>' && !isspace(*ptr & 255); ptr ++);
+
+ if (*ptr)
+ *ptr++ = '\0';
+ else
+ break;
+ }
+
+ /*
+ * Got the anchor, now lets find the end...
+ */
+
+ while (*ptr && *ptr != '>')
+ ptr ++;
+
+ if (*ptr != '>')
+ break;
+
+ ptr ++;
+ }
+ else
+ continue;
+
+ /*
+ * Now collect text for the link...
+ */
+
+ text = ptr;
+ while ((ptr = strchr(text, '<')) == NULL)
+ {
+ ptr = text + strlen(text);
+ if (ptr >= (line + sizeof(line) - 2))
+ break;
+
+ *ptr++ = ' ';
+
+ if (!cupsFileGets(fp, ptr, sizeof(line) - (ptr - line) - 1))
+ break;
+ }
+
+ *ptr = '\0';
+
+ if (node)
+ node->length = offset - node->offset;
+
+ if (!*text)
+ {
+ node = NULL;
+ break;
+ }
+
+ if ((n = helpFindNode(hi, relative, anchor)) != NULL)
+ {
+ /*
+ * Node already in the index, so replace the text and other
+ * data...
+ */
+
+ node = n[0];
+
+ if (node->section)
+ free(node->section);
+
+ if (node->text)
+ free(node->text);
+
+ node->section = section[0] ? strdup(section) : NULL;
+ node->text = strdup(text);
+ node->mtime = mtime;
+ node->offset = offset;
+ node->score = 0;
+ }
+ else
+ {
+ /*
+ * New node...
+ */
+
+ node = help_new_node(relative, anchor, section, text, mtime, offset, 0);
+ help_insert_node(hi, node);
+ }
+
+ /*
+ * Go through the text value and replace tabs and newlines with
+ * whitespace and eliminate extra whitespace...
+ */
+
+ for (ptr = node->text, text = node->text; *ptr;)
+ if (isspace(*ptr & 255))
+ {
+ while (isspace(*ptr & 255))
+ *ptr ++;
+
+ *text++ = ' ';
+ }
+ else if (text != ptr)
+ *text++ = *ptr++;
+ else
+ {
+ text ++;
+ ptr ++;
+ }
+
+ *text = '\0';
+
+ break;
+ }
+
+ /*
+ * Get the offset of the next line...
+ */
+
+ offset = cupsFileTell(fp);
+ }
+
+ cupsFileClose(fp);
+
+ if (node)
+ node->length = offset - node->offset;
+
+ return (0);
+}
+
+
+/*
+ * 'help_new_node()' - Create a new node and add it to an index.
+ */
+
+static help_node_t * /* O - Node pointer or NULL on error */
+help_new_node(const char *filename, /* I - Filename */
+ const char *anchor, /* I - Anchor */
+ const char *section, /* I - Section */
+ const char *text, /* I - Text */
+ time_t mtime, /* I - Modification time */
+ off_t offset, /* I - Offset in file */
+ size_t length) /* I - Length in bytes */
+{
+ help_node_t *n; /* Node */
+
+
+ DEBUG_printf(("help_new_node(filename=\"%s\", anchor=\"%s\", text=\"%s\", mtime=%ld, offset=%ld, length=%ld)\n",
+ filename ? filename : "(nil)", anchor ? anchor : "(nil)",
+ text ? text : "(nil)", mtime, offset, length));
+
+ n = (help_node_t *)calloc(1, sizeof(help_node_t));
+ if (!n)
+ return (NULL);
+
+ n->filename = strdup(filename);
+ n->anchor = anchor ? strdup(anchor) : NULL;
+ n->section = (section && *section) ? strdup(section) : NULL;
+ n->text = strdup(text);
+ n->mtime = mtime;
+ n->offset = offset;
+ n->length = length;
+
+ return (n);
+}
+
+
+/*
+ * 'help_sort_nodes_by_name()' - Sort nodes by section, filename, and anchor.
+ */
+
+static int /* O - Difference */
+help_sort_by_name(const void *p1, /* I - First node */
+ const void *p2) /* I - Second node */
+{
+ help_node_t **n1, /* First node */
+ **n2; /* Second node */
+ int diff; /* Difference */
+
+
+ DEBUG_printf(("help_sort_by_name(p1=%p, p2=%p)\n", p1, p2));
+
+ n1 = (help_node_t **)p1;
+ n2 = (help_node_t **)p2;
+
+ if ((diff = strcmp(n1[0]->filename, n2[0]->filename)) != 0)
+ return (diff);
+
+ if (!n1[0]->anchor && !n2[0]->anchor)
+ return (0);
+ else if (!n1[0]->anchor)
+ return (-1);
+ else if (!n2[0]->anchor)
+ return (1);
+ else
+ return (strcmp(n1[0]->anchor, n2[0]->anchor));
+}
+
+
+/*
+ * 'help_sort_nodes_by_score()' - Sort nodes by score and text.
+ */
+
+static int /* O - Difference */
+help_sort_by_score(const void *p1, /* I - First node */
+ const void *p2) /* I - Second node */
+{
+ help_node_t **n1, /* First node */
+ **n2; /* Second node */
+ int diff; /* Difference */
+
+
+ DEBUG_printf(("help_sort_by_score(p1=%p, p2=%p)\n", p1, p2));
+
+ n1 = (help_node_t **)p1;
+ n2 = (help_node_t **)p2;
+
+ if (n1[0]->score != n2[0]->score)
+ return (n1[0]->score - n2[0]->score);
+
+ if (n1[0]->section && !n2[0]->section)
+ return (1);
+ else if (!n1[0]->section && n2[0]->section)
+ return (-1);
+ else if (n1[0]->section && n2[0]->section &&
+ (diff = strcmp(n1[0]->section, n2[0]->section)) != 0)
+ return (diff);
+
+ return (strcasecmp(n1[0]->text, n2[0]->text));
+}
+
+
+/*
+ * End of "$Id: help-index.c 4863 2005-12-03 04:28:10Z mike $".
+ */
diff --git a/cgi-bin/help-index.h b/cgi-bin/help-index.h
new file mode 100644
index 000000000..68a898670
--- /dev/null
+++ b/cgi-bin/help-index.h
@@ -0,0 +1,73 @@
+/*
+ * "$Id: help-index.h 4863 2005-12-03 04:28:10Z mike $"
+ *
+ * On-line help index definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+#ifndef _CUPS_HELP_INDEX_H_
+# define _CUPS_HELP_INDEX_H_
+
+
+/*
+ * Data structures...
+ */
+
+typedef struct /**** Help node structure... ****/
+{
+ char *filename; /* Filename, relative to help dir */
+ char *section; /* Section name (NULL if none) */
+ char *anchor; /* Anchor name (NULL if none) */
+ char *text; /* Text in anchor */
+ time_t mtime; /* Last modification time */
+ off_t offset; /* Offset in file */
+ size_t length; /* Length in bytes */
+ int score; /* Search score */
+} help_node_t;
+
+typedef struct /**** Help index structure ****/
+{
+ int search, /* 1 = search index, 0 = normal */
+ num_nodes, /* Number of nodes */
+ alloc_nodes; /* Allocated nodes */
+ help_node_t **nodes; /* Nodes sorted by filename */
+ help_node_t **sorted; /* Nodes sorted by score + text */
+} help_index_t;
+
+
+/*
+ * Functions...
+ */
+
+extern void helpDeleteIndex(help_index_t *hi);
+extern help_node_t **helpFindNode(help_index_t *hi, const char *filename,
+ const char *anchor);
+extern help_index_t *helpLoadIndex(const char *hifile, const char *directory);
+extern int helpSaveIndex(help_index_t *hi, const char *hifile);
+extern help_index_t *helpSearchIndex(help_index_t *hi, const char *query,
+ const char *section,
+ const char *filename);
+
+
+#endif /* !_CUPS_HELP_INDEX_H_ */
+
+/*
+ * End of "$Id: help-index.h 4863 2005-12-03 04:28:10Z mike $".
+ */
diff --git a/cgi-bin/help.c b/cgi-bin/help.c
new file mode 100644
index 000000000..5071ca825
--- /dev/null
+++ b/cgi-bin/help.c
@@ -0,0 +1,362 @@
+/*
+ * "$Id$"
+ *
+ * On-line help CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.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 */
+{
+ help_index_t *hi, /* Help index */
+ *si; /* Search index */
+ help_node_t **n; /* Current help node */
+ int i, j; /* Looping vars */
+ const char *query; /* Search query */
+ const char *server_root; /* CUPS_SERVERROOT environment variable */
+ const char *docroot; /* CUPS_DOCROOT environment variable */
+ const char *helpfile; /* Current help file */
+ const char *topic; /* Current topic */
+ char topic_data[1024]; /* Topic form data */
+ const char *section; /* Current section */
+ char filename[1024], /* Filename */
+ directory[1024]; /* Directory */
+ cups_file_t *fp; /* Help file */
+ char line[1024]; /* Line from file */
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "help");
+
+ /*
+ * Load the help index...
+ */
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(filename, sizeof(filename), "%s/help.index", server_root);
+
+ if ((docroot = getenv("CUPS_DOCROOT")) == NULL)
+ docroot = CUPS_DOCROOT;
+
+ snprintf(directory, sizeof(directory), "%s/help", docroot);
+
+ fprintf(stderr, "DEBUG: helpLoadIndex(filename=\"%s\", directory=\"%s\")\n",
+ filename, directory);
+
+ hi = helpLoadIndex(filename, directory);
+ if (!hi)
+ {
+ perror(filename);
+
+ cgiStartHTML("Help");
+ cgiSetVariable("ERROR", "Unable to load help index!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ return (1);
+ }
+
+ fprintf(stderr, "hi->num_nodes=%d\n", hi->num_nodes);
+
+ /*
+ * See if we are viewing a file...
+ */
+
+ for (i = 0; i < argc; i ++)
+ fprintf(stderr, "argv[%d]=\"%s\"\n", i, argv[i]);
+
+ if ((helpfile = getenv("PATH_INFO")) != NULL)
+ helpfile ++;
+ else if (strstr(argv[0], "help.cgi"))
+ helpfile = NULL;
+ else
+ helpfile = argv[0];
+
+ if (helpfile)
+ {
+ /*
+ * Verify that the help file exists and is part of the index...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/help/%s", docroot, helpfile);
+
+ fprintf(stderr, "DEBUG: helpfile=\"%s\", filename=\"%s\"\n",
+ helpfile, filename);
+
+ if (access(filename, R_OK))
+ {
+ perror(filename);
+
+ cgiStartHTML("Help");
+ cgiSetVariable("ERROR", "Unable to access help file!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ return (1);
+ }
+
+ if ((n = helpFindNode(hi, helpfile, NULL)) == NULL)
+ {
+ cgiStartHTML("Help");
+ cgiSetVariable("ERROR", "Help file not in index!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ return (1);
+ }
+
+ /*
+ * Set the page title and save the help file...
+ */
+
+ cgiSetVariable("HELPFILE", helpfile);
+ cgiSetVariable("HELPTITLE", n[0]->text);
+
+ /*
+ * Send a standard page header...
+ */
+
+ cgiStartHTML(n[0]->text);
+ }
+ else
+ {
+ /*
+ * Send a standard page header...
+ */
+
+ cgiStartHTML("Help");
+ }
+
+ /*
+ * Do a search as needed...
+ */
+
+ query = cgiGetVariable("QUERY");
+ topic = cgiGetVariable("TOPIC");
+ si = helpSearchIndex(hi, query, topic, helpfile);
+
+ if (si)
+ {
+ help_node_t **nn; /* Parent node */
+
+
+ fprintf(stderr, "si=%p, si->num_nodes=%d, si->sorted=%p\n", si,
+ si->num_nodes, si->sorted);
+
+ for (i = 0, n = si->sorted; i < si->num_nodes; i ++, n ++)
+ {
+ if (helpfile && n[0]->anchor)
+ snprintf(line, sizeof(line), "#%s", n[0]->anchor);
+ else if (n[0]->anchor)
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s#%s", n[0]->filename,
+ query ? query : "", n[0]->anchor);
+ else
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s", n[0]->filename,
+ query ? query : "");
+
+ cgiSetArray("QTEXT", i, n[0]->text);
+ cgiSetArray("QLINK", i, line);
+
+ if (!helpfile && n[0]->anchor)
+ {
+ nn = helpFindNode(hi, n[0]->filename, NULL);
+
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s", nn[0]->filename,
+ query ? query : "");
+
+ cgiSetArray("QPTEXT", i, nn[0]->text);
+ cgiSetArray("QPLINK", i, line);
+ }
+ else
+ {
+ cgiSetArray("QPTEXT", i, "");
+ cgiSetArray("QPLINK", i, "");
+ }
+
+ fprintf(stderr, "DEBUG: [%d] = \"%s\" @ \"%s\"\n", i, n[0]->text, line);
+ }
+
+ helpDeleteIndex(si);
+ }
+
+ /*
+ * OK, now list the bookmarks within the index...
+ */
+
+ for (i = hi->num_nodes, j = 0, n = hi->sorted, section = NULL;
+ i > 0;
+ i --, n ++)
+ {
+ if (n[0]->anchor)
+ continue;
+
+ /*
+ * Add a section link as needed...
+ */
+
+ if (n[0]->section &&
+ (!section || strcmp(n[0]->section, section)))
+ {
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "/help/?TOPIC=%s&QUERY=%s",
+ cgiFormEncode(topic_data, n[0]->section, sizeof(topic_data)),
+ query ? query : "");
+ cgiSetArray("BMLINK", j, line);
+ cgiSetArray("BMTEXT", j, n[0]->section);
+ cgiSetArray("BMINDENT", j, "0");
+
+ j ++;
+ section = n[0]->section;
+ }
+
+ if (!topic || strcmp(n[0]->section, topic))
+ continue;
+
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "/help/%s?TOPIC=%s&QUERY=%s", n[0]->filename,
+ cgiFormEncode(topic_data, n[0]->section, sizeof(topic_data)),
+ query ? query : "");
+ cgiSetArray("BMLINK", j, line);
+ cgiSetArray("BMTEXT", j, n[0]->text);
+ cgiSetArray("BMINDENT", j, "1");
+
+ j ++;
+
+ if (helpfile && !strcmp(helpfile, n[0]->filename))
+ {
+ int ii; /* Looping var */
+ help_node_t **nn; /* Pointer to sub-node */
+
+
+ for (ii = hi->num_nodes, nn = hi->sorted; ii > 0; ii --, nn ++)
+ if (nn[0]->anchor && !strcmp(helpfile, nn[0]->filename))
+ {
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "#%s", nn[0]->anchor);
+ cgiSetArray("BMLINK", j, line);
+ cgiSetArray("BMTEXT", j, nn[0]->text);
+ cgiSetArray("BMINDENT", j, "2");
+
+ j ++;
+ }
+ }
+ }
+
+ /*
+ * Show the search and bookmark content...
+ */
+
+ cgiCopyTemplateLang("help-header.tmpl");
+
+ /*
+ * If we are viewing a file, copy it in now...
+ */
+
+ if (helpfile)
+ {
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ int inbody; /* Are we inside the body? */
+
+
+ inbody = 0;
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (inbody)
+ {
+ if (!strncasecmp(line, "
> 4];
+ *dstptr++ = hex[*src & 15];
+ src ++;
+ }
+ break;
+
+ default :
+ /*
+ * Copy other characters literally...
+ */
+
+ *dstptr++ = *src++;
+ break;
+ }
+ }
+
+ /*
+ * Nul-terminate the destination string...
+ */
+
+ *dstptr = '\0';
+
+ /*
+ * Return the encoded string...
+ */
+
+ return (dst);
+}
+
+
+/*
+ * 'cgiStartHTML()' - Start a HTML page.
+ */
+
+void
+cgiStartHTML(const char *title) /* I - Title of page */
+{
+ /*
+ * Disable any further authentication attempts...
+ */
+
+ cupsSetPasswordCB(cgi_null_passwd);
+
+ /*
+ * Tell the client to expect UTF-8 encoded HTML...
+ */
+
+ puts("Content-Type: text/html;charset=utf-8\n");
+
+ /*
+ * Send a standard header...
+ */
+
+ cgiSetVariable("TITLE", title);
+ cgiSetServerVersion();
+
+ cgiCopyTemplateLang("header.tmpl");
+}
+
+
+/*
+ * 'cgi_null_passwd()' - Return a NULL password for authentication.
+ */
+
+static const char * /* O - NULL */
+cgi_null_passwd(const char *prompt) /* I - Prompt string (unused) */
+{
+ (void)prompt;
+
+ fprintf(stderr, "DEBUG: cgi_null_passwd(prompt=\"%s\") called!\n", prompt);
+
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id: html.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c
new file mode 100644
index 000000000..292cfea24
--- /dev/null
+++ b/cgi-bin/ipp-var.c
@@ -0,0 +1,896 @@
+/*
+ * "$Id: ipp-var.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * CGI <-> IPP variable routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * cgiGetAttributes() - Get the list of attributes that are needed
+ * by the template file.
+ * cupsGetIPPObjects() - Get the objects in an IPP response.
+ * cgiRewriteURL() - Rewrite a printer URI into a web browser URL...
+ * cgiSetIPPObjectVars() - Set CGI variables from an IPP object.
+ * cgiSetIPPVars() - Set CGI variables from an IPP response.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+
+
+/*
+ * 'cgiGetAttributes()' - Get the list of attributes that are needed
+ * by the template file.
+ */
+
+void
+cgiGetAttributes(ipp_t *request, /* I - IPP request */
+ const char *tmpl) /* I - Base filename */
+{
+ int num_attrs; /* Number of attributes */
+ char *attrs[1000]; /* Attributes */
+ int i; /* Looping var */
+ char filename[1024], /* Filename */
+ locale[16]; /* Locale name */
+ const char *directory, /* Directory */
+ *lang; /* Language */
+ FILE *in; /* Input file */
+ int ch; /* Character from file */
+ char name[255], /* Name of variable */
+ *nameptr; /* Pointer into name */
+
+
+ /*
+ * Convert the language to a locale name...
+ */
+
+ if ((lang = getenv("LANG")) != NULL)
+ {
+ for (i = 0; lang[i] && i < 15; i ++)
+ if (isalnum(lang[i] & 255))
+ 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...
+ */
+
+ directory = cgiGetTemplateDir();
+
+ 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;
+
+ /*
+ * Loop through the file adding attribute names as needed...
+ */
+
+ num_attrs = 0;
+
+ while ((ch = getc(in)) != EOF)
+ if (ch == '\\')
+ getc(in);
+ else if (ch == '{' && num_attrs < (sizeof(attrs) / sizeof(attrs[0])))
+ {
+ /*
+ * Grab the name...
+ */
+
+ for (nameptr = name; (ch = getc(in)) != EOF;)
+ if (strchr("}]<>=! \t\n", ch))
+ break;
+ else if (nameptr > name && ch == '?')
+ break;
+ else if (nameptr < (name + sizeof(name) - 1))
+ {
+ if (ch == '_')
+ *nameptr++ = '-';
+ else
+ *nameptr++ = ch;
+ }
+
+ *nameptr = '\0';
+
+ if (!strncmp(name, "printer_state_history", 21))
+ strcpy(name, "printer_state_history");
+
+ /*
+ * Possibly add it to the list of attributes...
+ */
+
+ for (i = 0; i < num_attrs; i ++)
+ if (!strcmp(attrs[i], name))
+ break;
+
+ if (i >= num_attrs)
+ {
+ attrs[num_attrs] = strdup(name);
+ num_attrs ++;
+ }
+ }
+
+ /*
+ * If we have attributes, add a requested-attributes attribute to the
+ * request...
+ */
+
+ if (num_attrs > 0)
+ {
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", num_attrs, NULL, (const char **)attrs);
+
+ for (i = 0; i < num_attrs; i ++)
+ free(attrs[i]);
+ }
+}
+
+
+/*
+ * 'cupsGetIPPObjects()' - Get the objects in an IPP response.
+ */
+
+cups_array_t * /* O - Array of objects */
+cgiGetIPPObjects(ipp_t *response, /* I - IPP response */
+ void *search) /* I - Search filter */
+{
+ int i; /* Looping var */
+ cups_array_t *objs; /* Array of objects */
+ ipp_attribute_t *attr, /* Current attribute */
+ *first; /* First attribute for object */
+ ipp_tag_t group; /* Current group tag */
+ int add; /* Add this object to the array? */
+
+
+ if (!response)
+ return (0);
+
+ for (add = 0, first = NULL, objs = cupsArrayNew(NULL, NULL),
+ group = IPP_TAG_ZERO, attr = response->attrs;
+ attr;
+ attr = attr->next)
+ {
+ if (attr->group_tag != group)
+ {
+ group = attr->group_tag;
+
+ if (group != IPP_TAG_ZERO && group != IPP_TAG_OPERATION)
+ {
+ first = attr;
+ add = 0;
+ }
+ else if (add && first)
+ {
+ cupsArrayAdd(objs, first);
+
+ add = 0;
+ first = NULL;
+ }
+ }
+
+ if (attr->name && attr->group_tag != IPP_TAG_OPERATION && !add)
+ {
+ if (!search)
+ {
+ /*
+ * Add all objects if there is no search...
+ */
+
+ add = 1;
+ }
+ else
+ {
+ /*
+ * Check the search string against the string and integer values.
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0; !add && i < attr->num_values; i ++)
+ if (cgiDoSearch(search, attr->values[i].string.text))
+ add = 1;
+ break;
+
+ case IPP_TAG_INTEGER :
+ for (i = 0; !add && i < attr->num_values; i ++)
+ {
+ char buf[255]; /* Number buffer */
+
+
+ sprintf(buf, "%d", attr->values[i].integer);
+
+ if (cgiDoSearch(search, buf))
+ add = 1;
+ }
+ break;
+
+ default :
+ break;
+ }
+ }
+ }
+ }
+
+ if (add && first)
+ cupsArrayAdd(objs, first);
+
+ return (objs);
+}
+
+
+/*
+ * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
+ */
+
+char * /* O - New URL */
+cgiRewriteURL(const char *uri, /* I - Current URI */
+ char *url, /* O - New URL */
+ int urlsize, /* I - Size of URL buffer */
+ const char *newresource) /* I - Replacement resource */
+{
+ char method[HTTP_MAX_URI],
+ userpass[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ rawresource[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI],
+ /* URI components... */
+ *rawptr, /* Pointer into rawresource */
+ *resptr; /* Pointer into resource */
+ int port; /* Port number */
+ static int ishttps = -1; /* Using encryption? */
+ static const char *server; /* Name of server */
+ static char servername[1024];
+ /* Local server name */
+ static const char hexchars[] = "0123456789ABCDEF";
+ /* Hexadecimal conversion characters */
+
+
+ /*
+ * Check if we have been called before...
+ */
+
+ if (ishttps < 0)
+ {
+ /*
+ * No, initialize static vars for the conversion...
+ *
+ * First get the server name associated with the client interface as
+ * well as the locally configured hostname. We'll check *both* of
+ * these to see if the printer URL is local...
+ */
+
+ if ((server = getenv("SERVER_NAME")) == NULL)
+ server = "";
+
+ httpGetHostname(servername, sizeof(servername));
+
+ /*
+ * Then flag whether we are using SSL on this connection...
+ */
+
+ ishttps = getenv("HTTPS") != NULL;
+ }
+
+ /*
+ * Convert the URI to a URL...
+ */
+
+ httpSeparateURI(uri, method, sizeof(method), userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ rawresource, sizeof(rawresource));
+
+ if (!strcmp(method, "ipp") ||
+ !strcmp(method, "http") ||
+ !strcmp(method, "https"))
+ {
+ if (newresource)
+ {
+ /*
+ * Force the specified resource name instead of the one in the URL...
+ */
+
+ strlcpy(resource, newresource, sizeof(resource));
+ }
+ else
+ {
+ /*
+ * Rewrite the resource string so it doesn't contain any
+ * illegal chars...
+ */
+
+ for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++)
+ if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' ||
+ *rawptr == '#' || *rawptr == '?' ||
+ *rawptr == '.') /* For MSIE */
+ {
+ if (resptr < (resource + sizeof(resource) - 3))
+ {
+ *resptr++ = '%';
+ *resptr++ = hexchars[(*rawptr >> 4) & 15];
+ *resptr++ = hexchars[*rawptr & 15];
+ }
+ }
+ else if (resptr < (resource + sizeof(resource) - 1))
+ *resptr++ = *rawptr;
+
+ *resptr = '\0';
+ }
+
+ /*
+ * Map local access to a local URI...
+ */
+
+ if (!strcasecmp(hostname, "localhost") ||
+ !strncasecmp(hostname, "localhost.", 10) ||
+ !strcasecmp(hostname, server) ||
+ !strcasecmp(hostname, servername))
+ {
+ /*
+ * Make URI relative to the current server...
+ */
+
+ strlcpy(url, resource, urlsize);
+ }
+ else
+ {
+ /*
+ * Rewrite URI with HTTP/HTTPS scheme...
+ */
+
+ if (userpass[0])
+ snprintf(url, urlsize, "%s://%s@%s:%d%s",
+ ishttps ? "https" : "http",
+ userpass, hostname, port, resource);
+ else
+ snprintf(url, urlsize, "%s://%s:%d%s",
+ ishttps ? "https" : "http",
+ hostname, port, resource);
+ }
+ }
+ else
+ strlcpy(url, uri, urlsize);
+
+ return (url);
+}
+
+
+/*
+ * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
+ */
+
+ipp_attribute_t * /* O - Next object */
+cgiSetIPPObjectVars(
+ ipp_attribute_t *obj, /* I - Response data to be copied... */
+ const char *prefix, /* I - Prefix for name or NULL */
+ int element) /* I - Parent element number */
+{
+ ipp_attribute_t *attr; /* Attribute in response... */
+ int i; /* Looping var */
+ char name[1024], /* Name of attribute */
+ *nameptr, /* Pointer into name */
+ value[16384], /* Value(s) */
+ *valptr; /* Pointer into value */
+ struct tm *date; /* Date information */
+
+
+ fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
+ "element=%d)\n",
+ obj, prefix, element);
+
+ /*
+ * Set common CGI template variables...
+ */
+
+ if (!prefix)
+ cgiSetServerVersion();
+
+ /*
+ * Loop through the attributes and set them for the template...
+ */
+
+ for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
+ {
+ /*
+ * Copy the attribute name, substituting "_" for "-"...
+ */
+
+ if (!attr->name)
+ continue;
+
+ if (prefix)
+ {
+ snprintf(name, sizeof(name), "%s.", prefix);
+ nameptr = name + strlen(name);
+ }
+ else
+ nameptr = name;
+
+ for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
+ if (attr->name[i] == '-')
+ *nameptr++ = '_';
+ else
+ *nameptr++ = attr->name[i];
+
+ *nameptr = '\0';
+
+ /*
+ * Add "job_printer_name" variable if we have a "job_printer_uri"
+ * attribute...
+ */
+
+ if (!strcmp(name, "job_printer_uri"))
+ {
+ if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
+ valptr = "unknown";
+ else
+ valptr ++;
+
+ cgiSetArray("job_printer_name", element, valptr);
+ }
+
+ /*
+ * Add "admin_uri" variable if we have a "printer_uri_supported"
+ * attribute...
+ */
+
+ if (!strcmp(name, "printer_uri_supported"))
+ {
+ cgiRewriteURL(attr->values[0].string.text, value, sizeof(value),
+ "/admin/");
+
+ cgiSetArray("admin_uri", element, value);
+ }
+
+ /*
+ * Copy values...
+ */
+
+ value[0] = '\0'; /* Initially an empty string */
+ valptr = value; /* Start at the beginning */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ strlcat(valptr, ",", sizeof(value) - (valptr - value));
+
+ valptr += strlen(valptr);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (strncmp(name, "time_at_", 8) == 0)
+ {
+ time_t t; /* Temporary time value */
+
+ t = (time_t)attr->values[i].integer;
+ date = localtime(&t);
+
+ strftime(valptr, sizeof(value) - (valptr - value), "%c", 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 :
+ strlcat(valptr, "novalue", sizeof(value) - (valptr - value));
+ 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)
+ {
+ /*
+ * Rewrite URIs...
+ */
+
+ if (!strcmp(name, "member_uris"))
+ {
+ char url[1024]; /* URL for class member... */
+
+
+ cgiRewriteURL(attr->values[i].string.text, url,
+ sizeof(url), NULL);
+
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%s", url,
+ strrchr(url, '/') + 1);
+ }
+ else
+ cgiRewriteURL(attr->values[i].string.text, valptr,
+ sizeof(value) - (valptr - value), NULL);
+ 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 :
+ case IPP_TAG_MIMETYPE :
+ strlcat(valptr, attr->values[i].string.text,
+ sizeof(value) - (valptr - value));
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ snprintf(value, sizeof(value), "%s%d", name, i + 1);
+ cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value,
+ element);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ /*
+ * Add the element...
+ */
+
+ if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
+ {
+ cgiSetArray(name, element, value);
+
+ fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value);
+ }
+ }
+
+ return (attr ? attr->next : NULL);
+}
+
+
+/*
+ * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
+ */
+
+int /* O - Maximum number of elements */
+cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */
+ const char *filter_name, /* I - Filter name */
+ const char *filter_value, /* I - Filter value */
+ const char *prefix, /* I - Prefix for name or NULL */
+ int parent_el) /* I - Parent element number */
+{
+ int element; /* Element in CGI array */
+ ipp_attribute_t *attr, /* Attribute in response... */
+ *filter; /* Filtering attribute */
+
+
+ fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
+ "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
+ response, filter_name, filter_value, prefix, parent_el);
+
+ /*
+ * Set common CGI template variables...
+ */
+
+ if (!prefix)
+ cgiSetServerVersion();
+
+ /*
+ * Loop through the attributes and set them for the template...
+ */
+
+ attr = response->attrs;
+
+ if (!prefix)
+ while (attr && attr->group_tag == IPP_TAG_OPERATION)
+ attr = attr->next;
+
+ for (element = parent_el; attr; element ++)
+ {
+ /*
+ * Copy attributes to a separator...
+ */
+
+ while (attr && attr->group_tag == IPP_TAG_ZERO)
+ attr= attr->next;
+
+ if (!attr)
+ break;
+
+ 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) &&
+ (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))
+ break;
+
+ if (!filter)
+ return (element + 1);
+
+ if (filter->group_tag == IPP_TAG_ZERO)
+ {
+ attr = filter;
+ element --;
+ continue;
+ }
+ }
+
+ attr = cgiSetIPPObjectVars(attr, prefix, element);
+ }
+
+ fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element + 1);
+
+ return (element + 1);
+}
+
+
+/*
+ * 'cgiShowJobs()' - Show print jobs.
+ */
+
+void
+cgiShowJobs(http_t *http, /* I - Connection to server */
+ const char *dest) /* I - Destination name or NULL */
+{
+ int i; /* Looping var */
+ const char *which_jobs; /* Which jobs to show */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ cups_array_t *jobs; /* Array of job objects */
+ ipp_attribute_t *job; /* Job object */
+ int ascending, /* Order of jobs (0 = descending) */
+ first, /* First job to show */
+ count; /* Number of jobs */
+ const char *var; /* Form variable */
+ void *search; /* Search data */
+ char url[1024], /* URL for prev/next/this */
+ *urlptr, /* Position in URL */
+ *urlend; /* End of URL */
+ cups_lang_t *language; /* Language information */
+
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ 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);
+
+ request->request.op.operation_id = IPP_GET_JOBS;
+ request->request.op.request_id = 1;
+
+ if (dest)
+ {
+ httpAssembleURIf(url, sizeof(url), "ipp", NULL, "localhost", ippPort(),
+ "/printers/%s", dest);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, url);
+ }
+ else
+ 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);
+
+ cgiGetAttributes(request, "jobs.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Get a list of matching job objects.
+ */
+
+ if (!dest && (var = cgiGetVariable("QUERY")) != NULL)
+ search = cgiCompileSearch(var);
+ else
+ search = NULL;
+
+ jobs = cgiGetIPPObjects(response, search);
+ count = cupsArrayCount(jobs);
+
+ if (search)
+ cgiFreeSearch(search);
+
+ /*
+ * Figure out which jobs to display...
+ */
+
+ if ((var = cgiGetVariable("FIRST")) != NULL)
+ first = atoi(var);
+ else
+ first = 0;
+
+ if (first >= count)
+ first = count - CUPS_PAGE_MAX;
+
+ first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
+
+ if (first < 0)
+ first = 0;
+
+ sprintf(url, "%d", count);
+ cgiSetVariable("TOTAL", url);
+
+ if ((var = cgiGetVariable("ORDER")) != NULL)
+ ascending = !strcasecmp(var, "asc");
+ else
+ ascending = 1;
+
+ if (ascending)
+ {
+ for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first);
+ i < CUPS_PAGE_MAX && job;
+ i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs))
+ cgiSetIPPObjectVars(job, NULL, i);
+ }
+ else
+ {
+ for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1);
+ i < CUPS_PAGE_MAX && job;
+ i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs))
+ cgiSetIPPObjectVars(job, NULL, i);
+ }
+
+ /*
+ * Save navigation URLs...
+ */
+
+ urlend = url + sizeof(url);
+
+ if (dest)
+ {
+ snprintf(url, sizeof(url), "/%s/%s?", cgiGetVariable("SECTION"), dest);
+ urlptr = url + strlen(url);
+ }
+ else if ((var = cgiGetVariable("QUERY")) != NULL)
+ {
+ strlcpy(url, "/jobs/?QUERY=", sizeof(url));
+ urlptr = url + strlen(url);
+
+ cgiFormEncode(urlptr, var, urlend - urlptr);
+ urlptr += strlen(urlptr);
+
+ strlcpy(urlptr, "&", urlend - urlptr);
+ urlptr += strlen(urlptr);
+ }
+ else
+ {
+ strlcpy(url, "/jobs/?", sizeof(url));
+ urlptr = url + strlen(url);
+ }
+
+ if (which_jobs)
+ {
+ strlcpy(urlptr, "WHICH_JOBS=", urlend - urlptr);
+ urlptr += strlen(urlptr);
+
+ cgiFormEncode(urlptr, which_jobs, urlend - urlptr);
+ urlptr += strlen(urlptr);
+
+ strlcpy(urlptr, "&", urlend - urlptr);
+ urlptr += strlen(urlptr);
+ }
+
+ snprintf(urlptr, urlend - urlptr, "FIRST=%d", first);
+ cgiSetVariable("THISURL", url);
+
+ if (first > 0)
+ {
+ snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
+ first - CUPS_PAGE_MAX, ascending ? "asc" : "dec");
+ cgiSetVariable("PREVURL", url);
+ }
+
+ if ((first + CUPS_PAGE_MAX) < count)
+ {
+ snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
+ first + CUPS_PAGE_MAX, ascending ? "asc" : "dec");
+ cgiSetVariable("NEXTURL", url);
+ }
+
+ /*
+ * Then show everything...
+ */
+
+ if (!dest)
+ cgiCopyTemplateLang("search.tmpl");
+
+ cgiCopyTemplateLang("jobs-header.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("page.tmpl");
+
+ cgiCopyTemplateLang("jobs.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("page.tmpl");
+
+ ippDelete(response);
+ }
+}
+
+
+
+/*
+ * End of "$Id: ipp-var.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c
new file mode 100644
index 000000000..648d38150
--- /dev/null
+++ b/cgi-bin/jobs.c
@@ -0,0 +1,238 @@
+/*
+ * "$Id: jobs.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Job status CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ * do_job_op() - Do a job operation.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void do_job_op(http_t *http, cups_lang_t *language, ipp_op_t op);
+
+
+/*
+ * '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 any form variables...
+ */
+
+ cgiInitialize();
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "jobs");
+
+ /*
+ * Get the request language...
+ */
+
+ language = cupsLangDefault();
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Tell the client to expect UTF-8 encoded HTML...
+ */
+
+ puts("Content-Type: text/html;charset=utf-8\n");
+
+ /*
+ * Send a standard header...
+ */
+
+ cgiSetVariable("TITLE", _cupsLangString(language, _("Jobs")));
+
+ cgiSetServerVersion();
+
+ cgiCopyTemplateLang("header.tmpl");
+
+ if ((op = cgiGetVariable("OP")) != NULL)
+ {
+ /*
+ * Do the operation...
+ */
+
+ if (!strcmp(op, "cancel-job"))
+ do_job_op(http, language, IPP_CANCEL_JOB);
+ else if (!strcmp(op, "hold-job"))
+ do_job_op(http, language, IPP_HOLD_JOB);
+ else if (!strcmp(op, "release-job"))
+ do_job_op(http, language, IPP_RELEASE_JOB);
+ else if (!strcmp(op, "restart-job"))
+ do_job_op(http, language, IPP_RESTART_JOB);
+ else
+ {
+ /*
+ * Bad operation code... Display an error...
+ */
+
+ cgiCopyTemplateLang("job-op.tmpl");
+ }
+ }
+ else
+ {
+ /*
+ * Show a list of jobs...
+ */
+
+ cgiShowJobs(http, NULL);
+ }
+
+ cgiCopyTemplateLang("trailer.tmpl");
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+ cupsLangFree(language);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * '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 */
+ ipp_status_t status; /* Operation status... */
+
+
+ if ((job = cgiGetVariable("JOB_ID")) != NULL)
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%s", job);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiCopyTemplateLang("error.tmpl");
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, uri);
+
+ if (getenv("REMOTE_USER") != NULL)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, getenv("REMOTE_USER"));
+
+ if (strcmp(getenv("REMOTE_USER"), "root"))
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, "unknown");
+
+ /*
+ * 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 = cupsLastError();
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else if (op == IPP_CANCEL_JOB)
+ cgiCopyTemplateLang("job-cancel.tmpl");
+ else if (op == IPP_HOLD_JOB)
+ cgiCopyTemplateLang("job-hold.tmpl");
+ else if (op == IPP_RELEASE_JOB)
+ cgiCopyTemplateLang("job-release.tmpl");
+ else if (op == IPP_RESTART_JOB)
+ cgiCopyTemplateLang("job-restart.tmpl");
+}
+
+
+/*
+ * End of "$Id: jobs.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/multipart.dat b/cgi-bin/multipart.dat
new file mode 100644
index 0000000000000000000000000000000000000000..91c5bb5b4c0e039c6692bc116be57983b836be68
GIT binary patch
literal 50411
zc-pkQ2|Sc*A2*&9rDzq|B_%Rr#w?`BPPVcRhKw;7X3UtyR%u0Ki9(2yESWKleF-hL
z?2)A`$sUp|91v9`5(Y)U
zRH1ML6bXZ?Dybl0DylGL2n52F(j@sH!3rp-M_nDP0WJ
zU&?~yO7q1~a8j!yY1D&KngoKBIY*W%Wsai)#BeU417K|mZiRvlhK7^VImFSRqym8{
zDJiQcsVXP|jRRmyJdJ>p)AW)u`(r**Bv&b#I}U&+5=mZCR;Gq100{3z!+W_&S@=_F
zIN|}YCY|O^qR5%xvF;cgLCV4xhoc=(SI2p|0CVDl{+Jub8em;7EXf5J4c5WCy5cA}
zFD#B~FQp6xQ^^=C4vh1|5->!tH=RVoxi}NRUUZ@}jzYz|d4XL>1OkQvCgUhrz_wrv
z5ol2{UM{P`R6r*I2POli@FL(`X{)UjlYub+PYRyu2__ThR4^8p3kFQYdjV}g1)k&r
zrV=nzcW?lXLIRV#aA2A*2~2aR;Ba795}g8e#rxpERJ0QE&hQ48R)$b_Qd?E?{6TU^lQk7!URUdx8mIBG?N|0+YesU<#NDrh(~T
zAFwaj59|*PSkaFA1Cg?N_7f5fPjJCWL7*yNT{?v%1yNS|$pg+9Du6^F0WtE!i7S0L
z0s&8^;;CR4jGG%^m(@3pi&vSu5^#PTcL1S8U-7C17DEBd=0?X8Ry42hG1HZTz~HNz
zS2|W&tK|Lz_h&zFvUVqhMTcL=43fO#KVs>QE9eRk$kH
z)&&m)D~JEjaq2?y^#ZR%BPYTLoUq2yDV(782m1q|;!GiV;=DLUq~fqEQSd_z_CE;?
zCQ)2mfe2a&C=NIQMIT7!L<76~lidM@6r3BL1BG(|6ERp0T^F1iCr~+&
zy&BR$@KWh3aZOnb;vZ)iES-h}6X~4PzyQ%fcK;*(IWt(%iN(19_!v$S{1^q$BLaS>
z6Mo_M2X!w_uv0j34m8~{1lLu_KRT&DqJPCunyV41xynQHC%R{cU2J8M9WwP1VSHUd$FqY#0pb|z54m_HJ8^)lwCv6xj@
z%nucq6*FLfLh~Op;8q9YRtMvL8jSlf3co6YUzNfCB!mAUg9FUqwF*aC6(_BVlYSB>
z{UPvUlndSm&*@k-0)2HLeRUxHr-AezBm7q{(pHS%|DSG$AFG4%ud9O|uyBGc=*~3G
z38x1F)&i=>O1Cypi-GY!RuC!9%3}UQ6YPK2WQix@sEXz!z$5>p4gPy5t&2)mSia!g$_&-PvBH7Jx-4f4loN2Y=d{9xl5_SAb{Cc
zc3R3nQwvX{9>-CD{SO(aa9%Vi7}yx+3%bJQQH*W
z_qPaEeQlB3U%uLy&`8*;d^K%YsiGpYEl-0en?
zs-DnEo^@wXFO0NXiCe_W=xw@EPoHR=l&hc;`d};s6^iy8rCPH=-`}=%jt;X^*S(10)?5Bv
z-N7N7`Z+yL
zl$#orESX96K@YzAtS{tLm^3d6$ry7Db8J}K^~IOn(7Z8t0!jDDk@#N91`@-uI*YgwX9n|Fy&}pz
z1^;q3{pDA96q|Oe#bNf5*?~{tRrh-Dx`f)AIh4r;jxU&X?a4nB@g;6xU-P2vM-Yl$
zbrv}|Q=U`;K6Gd*vqky4|32T{d`IF(jxOo+*>?|Go|`xR);!+3GnxMG+swmbaq}@<
z!!OgyjdsM`EZ&%3xwj{EPBID}<
zWNf=g2Qsib8mpn96>EcBf
z+kugxLu>BRu%XQ6+0
zY+PO0J$MyU@=JopWq9T0F6*vFzjo2sA@sqB*mv?KHeXK%*l!99Xuf~+UhaIjZNFQB
z+ZjnoPybM6`q^u?kyX*;dUnc~%64_S%i50X-W{6+Hx5`wlY?y^w(9NwdTAli?ZH&@
zekiGeVcY6%G?LSrNHZGEDQ@vem^Xa)&UQisl^K2sn6ml)W0~2kyC~HJ2b-FGbZ{Lr
zv#jAdzN_#c8*$cQ&v@MDFV`u)N4oO25A4wJigl5F@kOWRgqdN%aCm;LO(bfcXM;e1
zVG6u*NE$_Sj>zfQVtobWJKO__=Vs_KM@xLtNEbWzSht<3r95j~6aZxUL&vuk9%0+n
z*d3_zK00B&p6Qbt=B4ssa9~Q1-BW898kncIp1F`~eJ91vii;7!jCJ3yW&OxwKZBP1
zsbCbno>`RlVSepc+0#cpfLva~D_W${h0kY@s2rCZON86QbFHrIyf9L#tbZVRbKwgQc<&2}d%HnoCMI>QrpfDfyA
ztV>CPx5*Cjs~Bu!5UwW;KTJ*fRQI-qi!sf7OC#m)=bn*%$u3*+s~U(-R*$nUS-x``&uSJo7ZW@!8;mbzPSEak>`$yVX0x7UV}2*%@(#
z1uaE3Tl8hZbMCoX-PW#nAA&j=779a|f19NL+AA)wZlMaD*E)WY*JON;u33U7P_R<^1ksx4gl`PBV=
zr!P;QkjXJRlFam+e7JS02i2vju?{6v?Xd^Lb`7=KlAI0)-syGMWlCN;?zUIGx89S_
zR^e_~NZ?*Em-O6dCDgQQMOFHDx(11#-B5ST$wWpWKGwzTAj8Y3j~r+reu+
ztA{V`aJ8Bte|6vNi5<`}=6%P5vZ$J@(Wy!%Up4K!KW0<0!+Q44VdxE}8!_A^=a5#6
zgt(tJJ1y8&5GsBieula4akPHN;SV8BUKI+-uiv;e*x$pAuKCR6Kfj@ErlH)muyGq~
zboTLr&yxUurw`T{o5>g8{L;^72i>isyCyFi`ZhVu3q&4&9vi#ADK=ln+SLB;tE~#_
zzmM~!5lWrlObQ8YDz04ShIy5U+;+k-Dpg|Y{7l^m_SY@UU@KVrsp>jbY}Z?CPJW7e
zes-ALcV(v6?FP&KXW}0`^0O^qH>|`TRqOA0m3y^N6FsS+gcOnRbZ|vxLqvzT*#Usx
z4XO>F6T#OCS^6fX7C1{6RFnyH*!QXEn@cA9Plpt@*d^?1nk(z*f3wB7Ej8QAFZz9`
zP2~Fr&g@`Yf1am`qPE`88qrM8?>DVg*{;D>$+Kno$gy)m?2MRLMI(ExS;rdBV{={f
zgyIIqrR!}Q-9idSY!bR2C8j4TO-E=%Ze*&wS^u}0Mt{jH8N=+ewKyHrPG?8jPnNtV
z?6SS)!2D|I6j4&13AVmEPidFFlb;tz9OOBz|Il8ui;GxOW0$dM6Y}-IJ_p~!513xz
zOoY!9(!`j2URU>!bH%m%==prZYZ@-`^F$D+D<-1X%*9NU@pKWydR%C{>?Ff5YLU+q
z=$rRL`Q~iC#H&*f!z2wEdi%UdOvWp`yiu~Rbuqsddl>F4d+%_j
zHIMNgqO9nS?)7ZPvbG0<;tCHAncCOaR@1qd7lEa=N_H_fHk%`|6s^k+qqpi>Rd{8}
z&wT7fov_aRQ0ksN6_+hA0`E_@!d3JolT9vfiDbw&oP5#HuvC__sI#2TB0m2^1sC2Vt+$kNNvGRX8A+3m#26l(ug~swsz7aK
zod0%?2`!YgO3x{hWpQ;qzJubuIJ2Bpr0ccxU9Nqp?^Bq`yxGYuZ%=N2b(*U9-Ei}l
z^?6~Vjo9w5qs`6JO97?DrFaRtfV$*ejQ@R&`{|)m^EH3~9ecL#%f_XM?u*wC&V1A_
zf_YculC4X>0vo{Zfv?LmzkUxKp1aR;!0vm7Mkz3;Ii1aOr}&Dde0;GX>7je*RF!Og
z2K|dMNyBJIw~bT8)grs36326JtsV~|uuWj3iz*!(O62vtThQ5FJ%0!#lb#c|kA-|B
za)4L}U~ROv-?1zgI;G9lJ7%wFf{^K*u-vmxcBrv{G}$(
zHC^Gk*4IqzAD5MLIONwZ?t57v$ZRyK@VWr^WDdwC6g;SOE_6%TlQt>*#?d@Z?zpNWkpZBIUv6fE(j
z8H~NzE6NyXco4qMCTiB%;x9mb$>4i
z5%V8E|9xZE$J`Y68YKnd8@CTmCbA5LM330WwagEC@cYYcTqujD0Z+WNl$rt#IySX#
zAhR=~3R@}&{iRRjw-}6e+aMn$YIVsM*AD9sqoUe2W=404s_E07h#HX18+(N7?dUEg
zBX2Llm4W)Jx-YgZ(&d|lOhu!D0;<#dW1)478l4eR}|Oa4vLiEQJ(O;-?%?8`$M-2Twq
zhIL&fwx^&MwsTKoIhT)pt4{yUO_h13KFVE()!xUheJVdgyXn&^=IqAVC0i?HHL)o$-{m=%D`wN`ELCVfF6dSr=i+AUz9TE!DM5@BFeeHFhJx
z5AI%cd?ez#pV_dZNxrtL3IT*ok4F6bezxm{&IjPQSJJ9odF|xe5+Kj#Z?+t3X*wx#
zOvAIc_h>~?AD>TtdpOfU;E_#KXU-RC3-3j^9go769fdDZ4sDjLnc}w4s-A@p)(L%=
zA2`%`bXD5l3@vP&dArLx+{z}wW8e0D@-6jt1HxNu`Y%TmDvNrCXsWe%|&qdOB&7TT_wp7ULjr#XzHGR`W`YRU7luja&EXPf{klTVn^XGu96?1N$c^I{PHk
zCW>|IUM{~M%2>D^Z^+!wJ4=637=ZrptFn!m1
z&E8j&->Z;yYAiVe6EPzkR*+jO3{_2)_sM)3VO7AOwsd~9_=-~NNNRAqeAe(>q3)>#
zQhof~eIw7x@%E4N-t5}w*E{c9=Hjr^s@c1*`8UL#q555=m8xV1-n(7NHD*0<0=)O-
zHgeO8^oglqg-6HskBC|NYcz8g%8YZVdYmltJN7PC&1YhpZj=2*tG5>jH~Q~j;AVox
zIy3o22?HbEJ4@0R-RV~>uj)SUuCs9>jCS0*d+YG&>yaH>YO;M^%)Tq#kj#EdB`h3)6vvuz(tzUr8t?Q|AAvGzdI)+s$p
z>$a~?tOzzC`tmO3W*bfT1h-s~-wq0QRpim$=g-jR*dolz(fpCgxk6EvbEDmE{_&h4
zO^fw$^J%-fr7d3_3hRuHm93H=V6NCLtg~5Cxal)$UcKn3puNx*lZ2;-Wz`)ZC0N$&
zv-dPy39+-M+SokV#=5|^Wd8Ofuvse
zx7xd*0!$^DhT%Eor}m<7=4QJ0pv`$Xo19E8SoulR&yh{b6WJ1$G98yPPolHW!zH?A
z)!Y&4N);|^nOCMR+QiI1*8KeJ^059UzJy1Kdp+Uco!mC2*D{-|#Mv1)3j^U=?c;6d
z;r&>K(V&H$nI1ZQClkLpfh-{KmyaHu&PS@#59;TGK8xG})qJ+*M*I1Qc_tP&z4p_n
zXsp_6yNs+id)NLfbl;YnpI=oTdb$WjdM0Xg+W!xw{GXb;R|_m-FY-0gF!00Vd-~xa
z^klpWuUnJ3$-Jt{$m{UZXrm)FqCDfpk#0HZK2@~8*O%jRWdEU?AH+KkUww5c^4;|v
z$Ab#O5-_8Sgi{UkNdXmDXZW?6APLd@cJaF9TUPk7-IjT^$KvuDcD*S3Q09G0v(Tc`
z)xWF%Rg*=QOK9wavczQOVey67Ey#DuADfstU#|pJCe+dCw#~Kd$j+v4^-edZz;EKm
zXO4J+Z^FAGo0%0wj7+^ai&H-SUDojW%;$m{EzN|nNvp3J0bc!ch=+NSr*W@+J7~9)
z6C10F{lYW1TFr$8p6g7QoVU7WRM=zuKhf@dsBX}J6w9ghtPyF4FlZcRQb_C2cH_B|qLQO>rfPZ&<1bOB7doe{6YIYntNz5mx>EsFMAe
zo<5n0dTQd#ank{N!&09@(`Zq~!}&unKvi{*1y!*T@xpwEqa?-5Ipe|oS-I?OrAeS*
z+tPXS_p#q|Oih~e-@Q+I0RK*$M>;!Kl#Z;^Z&A##j_EdKH`I!}2ynjET=2>}Rwf|C
zW9>)8*~q#?rhSK`@fk(_J7b%28zR#MPvbuOUdl{C*$0Yz!Il{oWR|U+d5C@yU0hTG
z2@_7Yc&$33ZBNRWkG${q;@VtZ!-BcIrwDv;3Pc@2eo
zKN^gx`GoowL0~tyX4|y08%_t_pij<6hFEoOOvh?QjE}R#K7DgUHuZQLPaKc>?&ZCm
zF_k5asLuYbr-%9$+rczNs<^JV&9tBKLv<3y^Dy2X^KLRYSIvh{dSvHxTCdCOi^vJE
zY-6&@K8;uCZj(+rp+GLe=^<1
zOucIO{d^p<+V!Fp=}w&F#zy`fuL6{Fe9@yDGIQ)Cy0!1dekQEfnB&V|_;v;%ZaX=C
z^TF*8T_>3E*?kh8b@)$NS<89|6waiNdAG^5S1bw?9Oz-Rv0
zLhZ-p2AwKaCVo2^sMN$ozBx5oz3Q#9eK+~6OZNoG;zn&ci6yo?#jg%diMw4G<~8d&
zxR4LRCqx%oaeMOEDyrS&XL_@JhULzk>s0R&LFK>L`01aE2W#sTrU;Bv)$j}eh
zQ~vRVIUMq@Uzn@H;s5=GdGg6qX$N3EJH~ahCZ!Ue1GoCi|X<42$m$^~y
zY15jpGmVd_N2ax^6st%)!o~w<>(_om##?NgdH8ARTjTT6(_dS^w=VURR`-6tXFwaB
z_%eSc89nsriiF{X-eud}@t=v<#e=Q)=j}?~A4e8wc)kueW%yLKzdM@xO<}vEzq)SI
ze3H@Vb1~_}+z)E5DW$I(sw=+Q=+|~u>~%c0C?eQBQ*B>w+C~nA&e}T43{tu_J=7ix
zH7eix%4m`5&0-m7U0>ccwiv%o-nL?I_x-&nL$fR1{#}}8PFs;(`d>;n#LLC()l<4`
zzM=C2)`w-wMme$99uyE}a$Vu#IbpE
z);O&fNEohh5>L5ua6t!@d)PXL=e4}d>tmD|G;zDGs{hz_T`_cm8w^uGUwkV+Z}oZP6gPP6*4fDY
zU%p7_u(>Y2uZlI@`|V0`yb?E0YRJ^fGRwvBb3WwPhk|#@`*$q7stVYkg1+<-`?#53
zJ-75lDvzSWO~ax=inlg@K!8`B9kjz3G)B&Czo)7lr(B9Ue;6qm193SJ#n_lOEfMne
z(UAOD-s1;Ig>r)A*-(_`O?N!JSBOcbU|y33=hHsf+3nX}M~W_YJJ>$W
z5D#L^Zf#MCO{)sIxWCiDa~XX}qQeg~C~>zmE|PTF6@;Qu92!p+NneN;Jl4f4FWbHK
zaYz$S0=l4{T}81nQgum@b3=hH?Dkqbmp-z4Pe~F+Md7ad5LX>N{0ZO2BlX_sZSK-0
zhs<}{JYeg)%DvcF6=YLYzQvKey{LvP=zW<-cS?DkP2-lPI8k;_i&f1Yk?UM)FG|A<
zU@0B9`WiZG;pnGajZCzaOI6TEOko7$GNI(ES%BN%{?irjMi5Wa5uYc)??z
z9i!zGo@d;x5xIsImFb?wx+GVr2%Ntq^(etnHBtdWJ%86xT)ppLTim*v6ZE4L@o;qV
z$J1*(gKyZzOqHH{Q=U;uk?HPS$g7ibNx826oEob$4sVW4D3!32mSaeKROZzq`#qwZ
z5s43;N}X1GwHb2klO!N09oh80N&evZz$pggpl*&M@@>3Q^e
z1hbABYL@?u+HVq8VB0E)i`x5w=T{aBI1v67O}>i6C!mS~N}e0MgCJY#g~+=kC@$RV?`y%3wU
z!5E7Z@_Et{(>r+HQ~aK|TO1jigrW0Z6^!T#zb=hD_)_>~b%rFhpI|j8KeExt@lxog
zi9O!2K)-3z()5w$GSry4@|{R7sL1&gd4$|qx`b(dlr+^U41?q{UtXgaQd=`HT(M8%
zlw!QFw_w;Poy#1~B|e`xefL56XV{sPLB0dA3{1nITd8T+=aRQ=r+e;audyD>x1z+B
z%gG0@E(qz?w8)}Il$=>DCj_vg9;I!V5p=W7wJK4Ynn;1+u|prysW=CDVH*^N7Ce%@Kw8lntrC#?@zP6Q@1lrfn84hK?fP%aI)h7az4p+$c
z21fP2YNM+Y3y7XBFI>28+N(>INGu_$>TNwseZ*MFDMl%V8t>4uy=Nw7`LmVZ3CbAoL#A#IdeqAE$`#+llp=!P
zkKP_`P(_ypGlVttTG2Ka;iE15WjDM_@*v%r?sv^<`rmPl#!+G2nys;uCBfZaj-%7m
z&iSfpEL|%eaz&`HruTM_F28EfnRskXKUf&)nMv36I2`7_S1qBn3UM?@R86gWTK98O
z+r6p*ol*%YU+=0x5x9pSFL_DjDA8GRE85&H>`--7UkXNOhd_5$bif;0<1m+{F#QSn
zNc&}&?FW0J&=xTkCe56`2@F&Hc&Rb}Ir_;XtAtXDKsUS1DFfXE<+c>=#Fj{CxaTd;
zqYs35K6Ce*wR~OLz7?G~b=n7HlIHWq>67HBpwb{_tOef1-%M9mi=Pm1V%dZD2bNqq
zKb6((5A?0;E;*4-XP?`c_TiQ8mMf=Pa(ZfJSG(`gb>vuzVT{hD`(0c0@vJ%NlG=!H
zbk2U(F;PUH-eyOZ`RyQzbhD$m
zZKB2+=nqXiwS_`B4ye-8V>QTh8)}3VR$i%^IxWY-$jEd@OG+#RTvR5^M3t$Ow}cFd
zAmn-Q*}klHQ5!qalDo&PCWc-gl8p3xcDXfHy0rb`$KIrqmBdqTKRSq^$E&>gMPg%|
z70^MFpaaXtBay6LiPFj|7pG3Eur$+7h;=%Zevl|OouH%Jmr`L4<(Cn$MnsyJo=#_k
z!p6onj!WCkK-^-Kgzhk{k-JrRs;N&_55_+MpO8Y2i^pIqn5z!JKGpkY3gDaI6
zh;PsGzbUVQ@E02QP(>e;k^YodQ6~y&JhlaWp(-6AFFAg4dHY%$@ff4ZmXI+3I&H2&
zxI{!CzQ=v*#yBBR{3tYxabs*!1??e2$K8}ndmY1?8!Y9CxX#63>@GDO16hlK3ZoPC
z)(L^87W5{cTJ8I=YuZ}!y#*liz2QoYs|0H)Y0YMbot%I?+irb{m*v;cE4%#uVcpVr
z4%)N+yx@mqO*Sb%2UPs2!77k?hMIHUb56JP1Dzr`fd0=vAZw7_NE<&^b@CK;^kSvW
zv3m~=c0X)XYihSK_B}us8VlI%c+%n|Vs8b;)WYVh$Zd^#$6!L~;T6;|dHo4dkCe*O
zhvBTo*N5&UrJgVO9%%!cY%DLU!_=K@ijY_6);x0?Q*voc$M8%lhB`1Ll$E4!&FU9J
z-?q1l|FBN;
zM&xDBZ;i5@e|B^ts42J%#`+j|dJz(u?}QF2=eH5K{vC68UdKVi#^aNv~4|+&w^jkO`HEHkal=U9{kk(t~ZQH(OX1VXknd`}W
ztqW=T4e0o4dgU_xtnq`}=!6N$mc!=evmMqNDU5QH_PL$v>xSixCsc}+M@=sr*k|th
z9$nWvptd|}p~Ujs>j$llNPtF!(+$y`Cc!Onj=aNV$#nHwAGx|@uMJtWL;x4wKMgcl
zazcOFdZwdyN=Rd83>eYfNr~8@2Hx3BtW4>*Q2`y0ba~c0`MkI9Ol~PCh*7co(d^fd
z{*sKA`H_HzQ=v)TyK-`Y{s-Uud>SLs7US&L1&NS66;=-Y0D4d9!>wo3nn!7s2g4K6
zN97nb==evS17dTd#e*e0wgvbjBK2Y?;-ApzO+v+DF-8GxamP}ZVpJ_0__{kG#X^#j
zF;jDU-pa)vizghi6{-W|rqe4$_klw)%(cy`_t%)W$RcBY-QNU-gqPRg)df6-cCW$(u_&-5_MyxDT$>_%@WH`
zd|l0^9J(Pccc(ichbWyT-?TS%TLL})cauiG-zjrKCpg
ze;KEkk7oj^5~rFIo06xLD!%sAPhE|O_RI#1c}8X42_11brS5Uv=0j>$@lQIBSaV-P
zgFbD&PkgQsrJZvTkYfRX^{Pm=!$Omnl{_!D;JpFwc+j*nooqN0#9wD+!t4x2?*M!(
z8`(JF=z}~#e+oYl|JdpQmFPWzsCssGC*#IcOi6YdX)T%V8noM+-uF!|cI`VeTukG{
zH_=JQrl`P}Mj-xh0UC^xpnLiED}owP@ztHL&Md;>pX)8W6s_1>E?a$dom-iKjAhpl-Iga836t&@P#oRb|F(0xr(2=hms4f!k-l
za9k*(ew8Ro56fxf?fb-|Cu9H*EV;AkF2USJEf73zp04FB$k?PpNL{yZiiF*yaxCeL
z^utV*qU53{8N5$tVj~q_8yrWoi_U4IzA1iKYL?lgVkg!;Ss7KCE5Pk^C+CfrGAfhb
zsR@3l?sP$enA3>tAzo{{{_ReEnlu3>J96#q&seI{0(;Bx1(5{qska_$ujWf5Kf?y8+g=gNfZ9Be(A3$z>!W*W
z)LyN($G1rWtyY^oA@&KIq(4S);Jy8pFQDL={vI*?>jG=+j$pS%uFYMHDM^ggF}Id3
zk&rzaCA4^2FfaNZdP8cfwX|qyL(q#dLmO$)UM`zbfk8R4{F=|a+jOg?uWpfiA1oR~
zE-(OZy0i}tP+{lbA6L9CK*^Wru
zeqnXWniwj|??U0{^qp6oM}zhY4}RQcAYVqlY@o6}Bt=ealc`dJwD_}H|2DYr=w`0V
z{PBGwSsRkM??i%1>os3`@D5d@k58yI?ByCV0B3!?D~`X7a4?-PI@WzI`|g$LqKz>b
zTyzhR>*WphJ;J4tvm$$lOX~v`*Y)ap1XB*KbBV9KDvf|?ul>O1CarzAJq7tJ$8VeV
z&gy4^PmONkHs?yKd%fAcgK%CrcdzM|H>x`hMzw8@jpZRrG=04i8@$L)9XDpbv}u;L
zYQF7e!cMq$&_3_e`4sqLS09X^ztyg5R4c_?Z*1fsSsK=Y8&P{I^-^~u5Fg_2~%wH$|^g!EiNhFG`
zEml>iNhyrpd_%58Q{|&+u*&D`betA{zr0WYQhRe5dDm&i`B%+bFM1qVn0WUL?Wet2
zPCVyg^U)cP%lHa*t!K@qzIBMZvfoWUySk5TuWyfgp=v1fu_aj8V29CuNxqhAh^xMO
z_Njqxn{T=ig=hLy?KY__ElOD!?~Ke_uby&aS+KEfKKepP=+wZKZ!)LJW}_Yk++!AM
za*46mN_FzK-jM6tzveT9a?9z?$M>nP>%|W9Sl;!oz>?e42h+YH^LLtFI`kUjtC`2=
zYxQ-sPUlfwK&Ol_f1}uzbMfES*C*c`tA-j0ehzDY=cM6g{$!%c>3x<7Yf`f|u_S`$
z`{CuPLw-ds1Ut4gyhNXQ%q1H5Ts8Y^#@VLO)=qXw%*QQsw(u?uLEaZ7H@M^Ww$fie
zPIMHtEzQ1U|Ni8mW$U~Q@0lmE+XMaeY_Xr7EKTw52ZeB{wdUI-sa8Vn9c<)Pi*G#V
z(DthN?2_-}?+?`UL6cBpU)m(!6(&mY$4y&$G}DLz#z<%zRq9H6uAne0cVN*m6%x
zLSx-Ie{j)P{mt>0uX>K3Z#3C1v>PO5bDG=d{S(3db1#c4$!KR{RnW+un>|e@wu%NA
zuqrQyPK`t{9J6mMtN)*8w1|y>)g`~f&xv7y9W}k+|(9##|+(4
zsLrc_IP`CcKWj^Sh#U-J2n7;nJ1g`9OVkN%16OgG>Jlu+@@i$2dg)>Qmvi@`A{ass
zlX34e?^k{v8OpRC$a4HPUk#4e4uJ2WpE3l25>94sMT_N)->O{Ndg00qp2?KLk-jWGtwGJSU3H33sP(WY&QO(
zeBfc_L*C`5wk5md-fKwY#JBwSp9%iFna~1kWp2p%FXv99kq?2vzP`R79ER#o^#x%`
z#6R!RgZz1u-hcj@V2tbA*A4{2oTZ%tVN=@;3)Q-
zKT9Y%fHkF7kpH}`0HXZwM6h%+6-1)A{X_%yZ!}a@K@cgpvJyyD3Z|mUp#f6{ss0TO
zaK@e~NiG!#7w-_o)KVcx?uwO7#ev5&G0QQ3*Q~>*N
z@F2g(fFq&5V5t5U1C9i=L*OtF6u?vZZ}0p!1`H1Q83U^HTMQTs2t{!Gr%E1FC}j1q1q942TNH=SuKD@csv%LpdJ!2}Aj}7=U)b
z=SoVzD+lj?@Hs^J*LlExhXGNAaC{D3iCrbwKlvQ`bL>KX$qy*}w-`tjj?V#qz*q2)
zzsG=cBIzfL-{$#h_CXLzf8fD?kD;vc>pXs&=MXp)@HrHU1gaMYPx*hqfczS}zs+-w
zl^`pgSjB_<9s>&fH3wDyQ!x>%6%)Dorn35`y7IP?sOGD=WWE~i=Bp8Dz8W;v7(k|weqx0DEh89^g9u<1QRcLP^_$@)$%I=rreqhV>caC3S^bZNw{D(l0
zsvw%*Po)i}@>^1zk|6~oh>8>fs3Ct-Jyux!L`wDljufzbAbuqUSNa_(IIu7){Xt3z
z`nSQQ`s+Q`kpD|k2*_Va{Wjv^2pA`{IHcf6_}|4B{MU$w{}J)_u+=3Ewz`(VRu?hY
z>KX`NUHn$yf21$`&tT^)u~Z;ve%1VED_#c9y}WP~;B?3%Im0eL0}y96+p0M~*;tIe=K9F8AZ9H!Den
zSS7=GDhuZs6<%1}0mLdHIu%DDk!gUoRZ5)6AeH_y`#;l0=U+cf!Bu_|{I`!paMgbj
z{LAMWgwj6={^i370`gCSf7$&bp#LcN>lPlN{7-^^`OJcV{gdEdHtY!a&w~H5>qa2{
zN$@Y*TEs7&`B@OD{ENX6D*vSMFPm|M>OVsNy4yu6{gdEdwya3VufL5vjsa4D^TY@*
znv}|Fx~($jL$2mCay6e<1C4LhpnR(cd@8FVDyt$tfk6Ko1bCrve&x7Az#RO?gP*8?
zX;#ina4vX^7Rhg=+`v`gQb<*(15ln;x3$#O2R>mfa5Q`HaUDIdCC-nw`a4do)i>?c
zH$#V&r!oNIdVq~qH0!~nV5<$F+^#lMrT!@T|M_VsAa4i(BIJ)vE^tB9%ZmiCgZx^V
zkbg$u-~7z;kDqTslvRK&{9k^)8If#Hl`YOqADCB=|Ee^+qwUUQV1oY#-8?~z3nyOjMAn`iyJGz1BqoWOLkIU_RKXbn(_gEQFnX=@>D0*x2Z~VqSisIP;03ksOt60h+ff!=cCBg}>7O2mrT5|nUtiShqCGO8Qe^_*)=urmo
zolH@axP#HdAXKCpQ@l1dmzWqTS(ZAJNhOE{$KGemWTfzkFQ$w7a_t_=jY1ty*9yt?
z9CtWcA|Gz@SmjBEw|%#Gms#7Jz}+g@Rpnm&rJ35rOl6yrfeQi{Pc>E4gTnA2g|~9q
zRb9UQpz`UyIyruA4U5=XA5_`gdkRID5H=|C0RJXfJPs=Xv);aYNp;LEv{2ePoY;R9
z6ka73cqTIE`J)p=ZA(?rI&YD9|B%ts!Xa_bZ)D*^g38@x5QSna?+nj=%;WLP&7$^(
zNMm0wYmHXV*2kNX$IOIOSlRyzP
zOD@a|znEr|i}erovBj~epT+fv+SN}Yo(3&E4oRM;%(YB6g(6S9nqf+IDLUF1WToh2
zK)%*UY$~>{t_}5H@Q9bzmi&Gt*I(pm170LEFeFF~hw&Vv_hm8h?`rAs24dS52ernO
zi-OTT80oe>T~Ug*W<_s%9El&}wt}+T3l^&0v1T4%!udZ#x7?IZ6&GDR(nW`C)PCOB
z4JB3;*`$38?bj@!XN^(agO(iZg4wlYL2vs4YBTV!u>B&WtMs>eVRL;aD9M=qqMFym
zo+ZAnwME{ZzAxH+x7qh5pl@imZ$1^?elyUZSmT?|n4U*SkSo+#(+@+i3!ZzM{y=Ww
zoHV*GZMMI>PD@Yc;H6ue(w9mHFsadzFY+SMZ*<}dtDelLZY(B_E-29q=UBTpJ3Lb&
zXEs%A!<^<k2FTRqH$=sdBie*3R^F4KNuV?iI;Ro!X>cbE7%kZ{wmlb8)9`sI|
zD$o1vqAo2)CT*@YcM0}M_KCRISAHR=m;BbZ%fh$LL)z|UgjXtMPF`=@OGX`ONG#_ilf#EQdR3s^?GcHB9AV1%uBfoI{uChn|
z_YuBEmc3;YAs{%kAs8NY!IO5d~<&=|edpTb%if
z10alA?t`@%MN#orPrcAmEYt{_?=8GM7GB*~>puPRKnL_Qm7dE>gn#
z7h5Ik%HMx5aFbWsZS>h=@ceBJJ_CaWpCmrxV6h-OHM0}M@HFR>ioUzTf)rjvyjOdd
zvO6jB^Jck=3@yd^17Y%DkN;3)EmwHCfFAr5?5z%Vd8c6
z@wDE`P;rGQ!T$H=Lh4PsoOdtlDp0xMxE
zMVc|ySuF35Zy0Uo?mUwB=xvBBZbGTPEkoVV(Dq9JhY=6?4FYa7j&>2`^?-}&239*;;dC|k?OYWvu5
z!tYC7*>>&Hx
z2S*jLf`#-@?(HWP3t-ykzj#bPN>fW@dqv%+rRis_ZQS9@>v4wgxUT@_abd752=X<6
z8Rsg%Kh{a)yI7NjsMB;ZF;Qaf(kuFw+p{x7kB8d%=8V=&b&>8IR)(;3+Ep<|PQPDp
zsfYGy!^blcAu@$qBWJ~os71UUb4rr0TJ(UyMFJBCTCLJ{zuXQCHoUT5xJojd4zFR`
zxl_up@FBi~X3mmX5&Z#vYNGJRzhN-o1;Q(rX~Z0XhmlZ-c|q97
zXI5rHS1I6Ge?)CgQZ|lxXP4L17ZmZvuuPQG7g>jU2$r`2n>c|>Kbw9h4w8i^=-;}Z
zg6ZEmci*xjxCHU~C@~D|yOYsDob0Y*HD}?PY^I*y*=M(<&Ea@)xK&4ymwi-cS8DR6
z&5X9Ciiyw1@)MmZ?cTr^ON5zIivj)XfbbQK*M>U=SUG)3e}BGb`;6!EF)KxEY*`y~
zV7Tri;A~D1AC+l@n$03|n|2H2&tXKT0O
zW=sckUWhXyV*2{Y4FMj#wb%T@Mn`u6k%m^YvuH%6dkw$XBE*@YXE!`M{pDDqU9G&w
zl#-ZwUt6`=!<{!Ii0PNx5tW_@NDG7_Akv$(AVO#fMXHE^0cnO_-wNv9`=0-O@1FCKZIeodSp{dPMy!K7WEf0!w~6As5S%~1;sGY?S=mbhG3W#QTu
zdqoH0OyIU!(~`E*rsEqto0agDEw4{&R#M5qsgkZ_<)f_mphKGL$%4>=Rk
zW*zp5+pKAC1ucB06dBHzZ|_ajGNlV7G=M+_=Ma_trAfMIkNKWG+e|2)S4OC8%?jPILer8
zyFMi+Ib&~R+jeEDM8L|zB?bg75x2je;XD9QzyKocBowO|y+_a-6nJ|@s_-vcxw?{vf=A&&b)w;CkkyIjJvT7Xw5^R(V
zsa^}l+8k}jq)pZ?pDaRW1^>5Djxub6xe!Revcb?tgFWOH0QUt_gwFC^DwPl+IgAi(
zsEkVv0~zLI83fvYZO9WfK)#h*Im-fJ|nz(NnnXVTVqkb!=n2*+wa#T+sHi~5s5EeC4EQ|dKR
z^9ZBWJY_3^D*72+3l-dOFx}57wMtms8Ik<
zQ)-C`oeDR-om}XvTlh8DVwg%N&(+egw&mILCzC{@LeUVO&0|`yklJY7`NmbX+7%i;)pk|3{szy;YPZuqjN*m1CQRTTWPza^Y@&Lu
z6aX}SLRCpCBfr3Msu*8-`njqXB12R@G7Ny|%y3gC`r5~!X?ZNa&}}u-+hLq+^2Px-
z=PsfYX!*EX6NGwgC8=h?;CHnb^~8j%e?cWn1}sbzu^eSS2K-E-27d*q*6~Ly0^WX^x$YS@rBl4Z{2BGRUUBf&byQt?1ZB=Sg
z#)q+Tfp?E7@{bVnz*yMsGSt2(jih7JW&;v4%swT2M=~OMTj*PAB#WDrtKr-+06RxP
z6`2Mw;iEwt)l&?BWV-pCyVHI^02VG}-Q~s8SR4UAavGW7K@0hwWz^&pCw-+dnO34l
zb-&&XYh4!BPi4dj%%WYr!+J5DBQweVc#2$*-?7pGbOc)hIOdyQ=~3&Md`zB{iXz{6
zgRB9@LTRL7W;pJXLEDX|7;>!*iXyc4
z%k{C}I#>H|7bOTcMLhy2i@OXcUUq-#&}0z-7-F-jr_@6YNA3j`?-@MW
z3PY;}ilYrVNXvzmP}ei`4ZDwjRT8-vo2^6W+Qy8PaKXvQFk0O*y^(?{gdTP;hjVQT
zW^T2Vnt%(2!&zGiH`?A9M&2pAh_Q_+EK8Cv|CF6BjUJ4X)OXd06eIIpSI
zM7W`o_g@Ox3eL(;NCq?PQ$@WI^(=YI*Vxl+Ae;BmVu|5e8g00YV%Yqs$Wx959`qnx
zc+tJ&QdwBTx`OmUhegTB&@j%07Lu)T&~AEZNadkby~W#g*q%^7@De}E3s8HA4QACG
z@n*@#taFf*OtAQ9U1`NIPL0Yy1EH1QJpfR{LhlzjZ!4|nA(keuCPO9=(_1}j2_GEv
z7^PCp7xnDjn9UiFtPV+c|CHP$UG|g0(*TMK_Q11z(S(w{kZ9F=qp8G@Nz9gEb*m0(
zNFxOjNL6?Ua;|PbhJlXyp$^217orEah6hZ(E{xu`?c28GoelK8VGA{_HM7ub_GhyW
zIEDTGA@OY_2icuGYWk?#UCF%c5@TgNyUZK!okg3c0KShToH
z*L6R6x9HNOf$5V!J>+OoaTFX)xJzoyQmY(q+ozz*vM1cGs`A!F0>d-cle0_p=U(Iq
zHvTDH`fz;_cC$7MZxP$(QRfy{?Ktx?TE5!e+LJ_nJsRQGpQ8pQc{I*g{$Fz48h77l
zRr1?5t6rX@Yes=K>%|y4!{2@w!wk7T>*P9H5X!~^Zzc~lF+G}M6Ux)V&1&Ann*-A;
zXqhu7+#oMOz|2msXEu8}Q^ewu!S@HLZ6UK+Xv#|eEers5;pGW8eSAkoPh|DyPP$jL
zUFT&rC$?9?70zcJclT7{SLiW19s=DQISeI0jZ|XVE#KY*z0an1pm%1lW&O
z0m0Ri&w4D+mg$O|F&nYozgb6=c5ND)yK$?M6Nc6_GITSrlVvt73BeWaBo;L#UyoNW
zks7Np6pxZUkM4?0GlCCTyUI
z(1+QrMGXey+U;O@AE|0O&dWmNF1=jpQ0qUZNu>5uQ
zGYgjE1YZM4AfM1cU6>QR-lAch7&7(@)wwergoTq!lC3LXk8R;W2G&>Sdsj#@Gig?E
zz*i@)^nw*!CLdKu+u||0l^jV)!hXZl?}e=oE7{GO}1|
zmMFi#0xyh6Hj16+<97d2)3-Wrib>R{mRWH}4b23rOaIqVZ;$0q%ao7FC6DuQ;0^+4
z3zi!81qVA3G{L&ky7a!Z0|fGfFVP%v0-X*#;nrx$reT>ee;wPZZ2;N6$TsAZ^_irF
zLluamofaEbG?alF;Ix}ca+Pu3k)Y}8{O*}$or9F53(_%1tAtj9whrVoCDl+2!w=Oi
zpH2m5idxaSi8*KNPOn@sn?ZUBay{5`;U%*4f+d#hJy{sbkx!pu0AB!iDr3@B?swHL
z%(*Xt^uz{*U7<#}ozQ_oHhSY&LiGA6pwY=+O{?bzEhmcnHk3=B=Esl5`1Es{Z=4)*7~VYqdQNi$AXw%shNnKjE*+BrM3VH
zQP)754#K76l!2)gMtH=LMqGe|(RC}D9K2aeDFWLE6_Th1uNKf#_$mPNSqMy~`P+h!qH7m)kV{t3$p^G^ivJ4~%T;_(((B(Vj)pSAix&z`0Z;-a9uvZi;
zG9JAG>*3ey4PwxNJIo=^PSAm$-Ocqhf1ym{W=@@Q_fs-T`Q3yT$ZPx!->bZ-yYgYk
zyYk5@SDxBm%BV@X8=TC?%ul$&+$#R^BKp}CfSB}dU_k9spKlEv^L5K5bxppPqO(`E
zcDj{CocX)1{1Tz={^Em{uGq6sg4!h>aGWv|9=Q4GmX`tU3bPLWE_0Xa6
zSRr|Wr|3Hjcoix<>%Ii&VaKv|)WWU1q}V&Hk2sT2Jnt#r=G%&%z@*UMf%7R`L~{hw
zCXhx-kR42UXtL-R(NpxFN1STE01KGYvLc-TlOJ`u^;3(R3TH{8R|t@ebxo+)iG2I;
z+h811v`Y8~`I!&r3jsL;SIDk?YJmvx#LB&uIOD5MBzJqM?L^C`xkPu>HIqC
z62QLlD4JSg9Is06hj%UbH`P`|SC2<@kR3#pb)tnM7!=3Dgr~pbA$FulC-2B*WOohV
zj=aJgSz{3{0Xq;kl?~GqSzc^Z$&Q|)5WGRS^2!2niNWa{gFFx@WgtLWV$V*9K(FZJ
zox?u{B7Fx8y^?Lqd>saQIV-WowZ3iEw9+k2t$?b(MxCDOn(<1RTH#r!h)OnX;u)GD
zC^IH_=5BM?{Y$zfua#MDTz%D4xA_>!voBh~X06=3qGU|n0ytX=n&cUw*(KwD{|wCl
zpp)O-sF~gWZGOsKc{tz87sy}vCqMJ}SfMR5O}_mln(#CBuPbMQ@7`yh5X4(dJaeoFE%;d|=vS(G{9!+WaYyY8P4z{oD_xe>y&i1um1zoiUs>FId7|Ygy~#xaBs^&>
zhk{z`zh*q*!|#lj7qYwL;k0+H_LVY6%gI80kjj;|vAeX>2|4-bBV7i0eB>Gf@jW}S
zfF`^1=nnSEOHiUdk)8gkmYk`Jf2>70xgg2f$u0^dS8wgl`$sW8#ZRz4)he!_c{Inc
zzD>O~oF&kefP?qZB`?$=^vvX1e1M$0+GCrWSs&%le~aYgr=ykFPBAe)+z>z#92%zGt
zxp#mntg#0w5v%~>BXba~f!u38jE=F$}S@Uw4-!&o%LW|z9M(jqyJF8&Y$Bm6^qE6y-K!!~SG
zEX_L%_leys63rf1Bz&|$Pt3nlcA~|$sRmYGiqCK@k>xR3m>!52%uyCSB^*K@uJ?^!kGy?5+G6Pb
zmdpV#S*sef)oFvG4ORD?aD}1gU&mdtwV@X((J!=0v{-r&VD%pyTaNXmAL{n~Vhl%F
zHR|${6F_?`B~9lvV#u)nY)bfl6O%E$Ypb!EkRAP5NlHFl@CY|Tjm&+Ye0cEms?B6uZ{X3G9wKEFmo{O=C2fdph7^)6t@K3YGQ?G_&daycB=YpS&x=&eUdc`$UU|
z5|bDOv2tcbcCoToIhK{AA%cHw-IcCB8GduJAldJ9{E53DcX=VbtPs>-(FcACj>-(V
z)5?-wYM>zTJPKf1TnwIid@8)#3k&DFcq-26tN6wE-irtlXY6uD-=-{L`t^Jw=x|$S
zI#Hxf_AY2MTR#SsH&w+0zIBxf#)r6dF>tK^uE3qkRTOxU;Na~z5NBny?$^Z9`(t-;
zF~*X6;}(d9oH#z0jCYV!YHRuwuXB|}rqeIg0vl$kY`W6zSi@W;hEAC6}hOO-HAv!*YXCbVTU?Z|ckAicm<88!6CTeWPU-;r
zMLEPf*0W?{m!l10UiDNeY%X}gwmAxPX5t(~uFn3}Aafe;R}pbgUGR1RimxVM!Qgap
zQ?I&LWc9t5vn!lnNS$%J#z|_o7Swb356PkW03K(#wlkLeQ&0oJIwt%IZTR2FLFdT3
z%Gs)Ir{d70CB@Ur{puI%XbQsEtN;kTKe^iK+DiHAGH1h*`0nH~10pNd+LM2T<+-|*
zLG-<8Vh8cQcQ*I{EBB>~d1nQK`+;3%xYu_y=0n{wo0|8747}Q$qQ3B*4Rr|nY3Jw0
zymbrgj2swi=jOdCdv6}}6bpR>d3&2F5A_zq){nc6J-Y2OR?|DVv0i0U$P9^A89S?h
zf?JilrbXCe^6kAdkp9om$q+;SQD*oUAF_Nr48j3bNC_;MT<7==+l4GwF_}g2ZN%U9&pS_G2WDlKEKPFwssZjK_Tkv)Edaq7BP)jw|d
zmpsRrjO5*y>Ju-ure`6iJCHfXyA}2SP>!v1k4xwR`SbFhGx1x9n{@%BP*oZ7PM!_M
zY}Pima$2A<`vaWQEDt>u27j0J(rW2z5KVDw5%WYtl+Fho!`$D;@rv+YM+fai%w{8D--Cbr@8q4)
z5AlhGaRPY-sq^WoTT}IaX+-DT44(>14%Y_>Bli09@_%{eC9-28diyhK;{~D0r
zf-oNQu4A4E9cTu`kxvo;*_XOP*#>a#P8@EHE`2~!P5n4u16~?Auk>itmF!z#?3KDm
zAfYP}g-4P6^(cUJ@AR!YW+1cQKe-08WRe>wgTQ_Vh-<=i1pBu^l1nUI=Qn2;&w&wv
z(-)^wzlxa(`km3E6K)l+3!Wl#05xK!0|~gs+BKf0*n*m#jey`P1Y6#<;t~Zuqe_g9
z60VEEc~TgriwkALq>!IAOhg}@Agjaxfj2()g79~Ku%9MNJ_V@uz|*Jz?NWsS$RqBF
z_r0zhwYQcgqmHUbgbxr|O94jYQ%_UV4fs52derj09ZIS7%(&N1_^EL-+%+T_D+n`d
zwD`&gzlq4xJX0B6z0CHLI+~Mdc|rb6rF|r-N(eUkq>8tY74p=6OjPd~xeI2=79T~1qZ~^L^j~oIZ0U+%-M(3Tom)>7&88K&?
z_yd!FiUoYmOegP#o;bS^U1Vv3EX}p)*+B1{DTbcfy*j3v6^hW`en*LHK0d}!oHqqD
z1smS7>x6yKouh|Aw-A9FXuLX`Y{2~A=}bNrd(bka7={EgdvFToIFnm^380%@`MFWJ
z{)1eA>~TP8EW!AWo;Vrg`Cka8OXz_|Be~3W?EivnPD2@%nHobD62XgOOA&wf2CpAg
z;pFb9lSd=WPY7kRI
z_;SKJD?D?Icl?of+O)w0Vtbbl}M)M`SM`SS(1;Vv&?
z=D~x`WMhafU1MtOK(Ls?lWh;x-Ds-7=f*x;aM+lwW@)6+wY0d`o{FCfJdD?LK+A%$
zjt2Kencu6DpXC~H`|*x|Y=$wbI8BQNqmgZw&+=k@=L-b)$Jmk~Vb^N$H@FrP9u-O;
zVCEJq1rECrd&%5JsMGv2qux
z*_fAh#j=5L<5AbAQaL&V(b*xVXSMGN#jEk$1%1X@l%xedxC8g5>1V75$_xHJ1@UAX
zKH7YqcTxGT%7=hVX97#|&|R-FVbMV^S2nhhqQG2$nQSsNHiVLQlSaZz#ZCZ}de&r(w6%&``;nEQet;SS>a
zaiM&M%dv3*V9pRBs##v2cBw6pM9kQQjeUYT;G{x+kg%Z7=5>V5JtMjncxTD$g1$bc
zP7@2WORGJZBN8sCUebo7RC#skERbyO79x}D?_-)Pv=_eWJ4gCFYlQ^p&<%BMHiOz7
zg$Z_HojPR3=jIQb=Dl4eNUWi?45P%pybsc4-opKPtfKMDR0sU9T%~cfCqA~TyVe)>
z)QlaseXi^Iy_LXUYM`X+Nv)N)DMlr9U!A^^D==KZu)3ksC8pYN4_&-)OVqz$kzl7O
zb~c&KEQ=L!R{fFhDt=MIVr&-ETKD*4#Dg`RrsLIt-RZ~K;O~XXJ^=T8l_$iX#=SO5
zA3rX|P*p>jMb$d4E+|N2uzguWFRO2$np5UlCDp8Ha2=n4H(eA^iuW7rn)r>_sD5
zT=i361N&oOy1PaID-8046D@;gFzMkNE?MA{b0nTA+UZ^y*gGCwOyUJ2{Xo4dVEF1>
zR+v*{pSRtR)LeU)M}h{TMbmqT@a^IIgp-$|`+~FGZpaB0jVZO8{xus=iAp~`2=+MH
z&zWSvnMbl!b!~iU`I#~B=QS^emU7r@u5?u%Wk*Zo
zxAub^a}=pur<*)SWb{66@kev}A|&OH*Ds+9ZN9wk)0nFYv5{LW6%VJ$w=b9*%a1qU
zeC;AVQk64TF*>e_rCBrJ-mL5xtw}WCJhn0jbwv$=7llnNIz9=0(->I;mmjA}Y!5UZ
za#D~6heVEBVm5+R5%(;3FSVq>ZDEXS2HhpUogy@%-WA!gV~hC1ijpP%!H%}Go3^1j6OEi0N?
zHGsB$Vmj~B&mWYX0U``~Rk)Wd_jxNe+&YJu=HAZO_&%BGzBKmNWx4a6QO}sOyi%fb
zj`ee`nVu2cAD0NVx{9?^^Lp+oFJ706=#k-DzF6LFr}n|1T`ymc
z8|F>)y*6VVS9sv-|D`cUR2wn#aIqC?W`RBSX}jdV>)wHrgHCcdEY|c
zQW%%aw+9K<&Kh2oT~5g9ZvJ=cdexnF^BEP-kONqMSM#NHt!v)DTdB7=v&`gjhW+nPA&IS^l7djWpjApY-Scy0P0n+h|7%GPB$Zk~^3x
zSUKxcE`hHy6U4RiiP!2I?-cLO<`(}53UUlb)N|sT7lR@u)kg;$gGPn*O~nw|E2T7j
zry64p6&v>#M~fS_5f1YElLzNQBP>4lhEhQ7vQU+kCiN9Qex!v-Y4M=#nYF#naiSY(
z%Z;=%wZ`pyxIHjr3Ni1iPB!1%*R`9Qm^j$+ishD*l@$-#?^!-{Cbf{pTNcJ!02so;
z#ksN0-!+=Qyu==x6+Y-8ZqEqqsdx>XS;2Y1&iMY+Obuix=UD_3GOw;d(kFs^eVl4m
zq4)^yHvac5EcI-=k~(P_a+Bl!RkC4GyZ(~(4fYN7f!qCiYg?p+xrI6Hy#DFMT+~p~
zRxXcH*>>lojBJ2UgWn-fJQK3681oc@b6#3TaT6niak05cOu_g?mO~F^ynyeWpB|9@
zm%LY2Hd@A2N!u;s3q;}$acyiY%?y#YJdtX4&4S?+w82F*;;lbT(uJjPV*dH8mGsVD
z_i+}dRZ{se++@&x!Q}pWM0$5<_zMop7arB!#Rmu6&d7yX;_CML&iFp2ID*0jWNa+ODJ@3au-4}yR$sr(pPbCo_=Rbbs)CB*PV5x5L-X+L>?&Si%jqK$K)qR+
zzKqb&Cob>a8Y8-29-Ek`4@dFo%q;N`rl!IB`ezQ3E_?2Gu8+$Yvj-}F-h}kS4_I4~
zjj0phDaxSrsr7YYPyh)x*OOk1kd>)7k&$gY9MFA#MVzLIL6kRMGSoOOYJYJZ*EkUo
zZ&+v%kHx-eUU6i`KU4R`dGAxJkt0_Ky>?vagXE!v3pM=7bXeK*#Q%
z#GGxU@R!QmxuDb~4RfU2xXkPBuN^kw-}eu8?p7L9aU86*EGq~>4)>?M8W(D8cJG}D
zkO4RP?8;5NyBl|Sjn!?SZl7ssIe?h1(KFW;w!5>mfBY(ogV5rk|CG)Pxj+U8l(aKE
zrhP}F^i9&?_}(MmD&9^xlfy^%ue$~KafJrbVD1HZX$f9buwcGruiBQ4>8J<=ax
z)+n9I-ZejW>*q9)c(60Owz{^$DX=+j&OO9y(X*@|bFix+x3{%&03|7ah&vlgJbMek
zjcF)pYL)b?pTx7fHYLs1Q&H7RDOV@w>KJ(X^CPGnL$$BlzWe^tl594j(6{hG{zspE
zOrvGk?n3YE;W^1P;arCX(`Mn|;dO_tf?Q1lKF>Tr9@#f#MMzq=xPMG^D^x)p~iC<|7Y4?J9~oP4y@FV`$QI0KK~-jy+JZz1Xy
zoEfPfYDcyE-QQjg+In)(g)!JEFcICK8eK>VN@dv}pLTo7r2l2nD?6S`l(_?R
zcDC3N&m3ybD46?0*OsGm9!-Xgm`(=P`Ms$CS45l@JJ2Qdw0j9VchfTBitWG2y>d(&?owrbbidH)DH^CjB!H(R$0mkmA^7`41ub89k$Kk?B<;bTiVA
z-81YQe9h!uCu|dmiM8|bCxkU}QMKtUGHaijvISy?hWgkSW<#n|_8l0Ow7CQJw|AaT
zudNZs171l9+#(2^*deZl-PgcyHg69_?A8XQb|W7{bfRY0R(jfnd3Zx0!Wuof4)b(~
zmM?4DQ3i@L5oue*)#uh;-3?M2RR+M_;F3^DeL3o%yu%QhwUJ|R2w0sQ-9+Sg-=g@LEDUN5jMDQ!g_9xQkb#ow9ICmx($
z6da$TsVf?L;Vj?MvH9t3yLwQXAK{B)Rl!%&YccxlrD0~5_YxQ6V^rUAUsYyrkWM$t
z{DjM$`!bDMTl;{<(tB?b_f?~t`57-vbzG6Y-=i7?UWI)*peft!EM{*ZBkDYlUNb$4=co^q
zJgCZFBp%kb>mL@5R7|eni@7Q}3Ywge`EEEgx^W0qgD{yE*g3f`e2`Tz{^H=T!?Pn5
zH9s!TD%kDLsunJdu2M;8t2Va6gNg9KAN6;jAXBGv&32k+)O6htb__FmAk(4+KZR-*
zHGM9BP`q)IPC0rbCS!~iT~Kc7e612-3*e$BlL@|uI+NKPP*|={MHV$kuO<${3H*T4
z5Ib<0Z!`!0MefA@ODf|pDPetN>U^Ygc%LSM3O}&-<(D)wZ8Di|kyqf45~C*f@@}bL
zAZmoz2`97%s3q->ZdZ7OKN3iOI|wo5f6?dRQTsMg6Fr;*KY+zn>s*A1Zx+CV
zDZu7lsdofnx1CP4SZH=8zh(XYut>d@=fV^l`!k09eESD@=xC_}Jvy348+f~G`Tft^
z7EMNKZR`t7o;_Mf#`3mylRG{IiQp8TiD`-#vF3-@Tu&AIMSwwfdkDVOZhA}>c3GE8
zjY9#QiAG_Uf-}^`!qpU^V5hIs742w_<7h=F#L3h-5C2PrpFY>TIP9Yi!5z=U{gdHH
zu{PA0%~v7SmOhykJpP_5A`W6|SBi|p5&VIeK-+BLumy%0w3T8}?itPk
z3_$O|sZb5PIz6?q(!`f!vKF7p${5peM6)hCc9R8xx$BOuC7#2a$pjMpjC$IoDMk?Q
zUwq&10j~xR=scF`0l8x3gI?i}$e&Nf{CfTV8emr=AjOSn2izUevnU>Rg194ENyak-
z8O{Rs^;|9?!~5Rgpos_hT(SH9iRBB_1hoJ1wmvFF>&z1kli(xYplrq07O0N=xDFft
zB@&4k
ziLL(~bO?h2h+zLKKaTHP;G-$Oz+$NpcXj(vtv(_>C33Y2FVg{zhksfZW*l#BG(O(ogVf(oH8*^u-}gH
z%=-QLi0bGdW6PH>s>bBtVD60!wd~~Sh~U^k<@tTFcVa}c2mM;|;w_W~w?;JUIF7^J
z$3^3fu`iI$49D*V^OTp0MDLxVCfFH?FY(ic6C{VYJ_*8%-G_ilr-mGF25cr;IW1|<3xAgaIhPGKUT)-(J8
zWz!2zs5>Z6B%C1c03;Rgp`S4M!&wwo69EVopRm@1(dXqX3F&pRYeikf*#VcBzIxmn
zEO4nGF$lbBs?J0Wh=vpP-asSR7ceO-HzZgq-%4!2oXBmI^mYiXU|kM0%rzKr4KzLq
zjmv$dnM$dQ(&y#dZQ%q3aGpI-v(EH*9-x+3kw(`cJ(XL*F%1a4fpDzH=>ni#lGb}U
z$xRqrv%~-o#=tKZy*1E}lId8XV)fJ68+(_>%DwiQ+!qDYa7X=7klx8zvvWApNN&r1
zOiFy8AeMRBW#?jE}M{X^(;7K*AesA+#4|3Yc3LX!K
zQyqt|dY&B|K-%{~n@k|5r)xL`6~)L5g7iemWqaN(9fVV794?V?;y7F!C0KNSv?win
ziEfsX?Mo(SeWQH|(xMZNaJ(8#eRZ%T1sRSb>;%qpP=Fawm-U+xf&%2;w?;rWFzW~Bj8QP=ugV+fF;xZzBDF0`_J
z%FW_HT#t?$ULso+(UkZ$Q4Aj~h}w}Hk0&DLwFFza9ERQ^Y0)U!3P&T2GqVA8O}VI~
zD8}(rbBK*&n|rcE;kDuZ^Pq`5f6ljS^^DW+m4qj1cRYY;V~;|kL17kw~9l+Jl
znwUoIFsA^q;X>C|JJ{cL9|tBHveX9eIlqplZ$KD*VGUYc_Zb-?dR`p1b%72erP)k5k_t$VinQ_=|Z<@=uB&vs)h6-
z0E6gLY#l$lfA6mqLjUd$61aV5Ul!9=u}8f4LA{s72c=%X%UaAG`EP-21f!-|2p)82-!zKLtM=j
z`~7ZB>9fTrc2OJp)(208OZD)K*C~8pJpx~Fq#LS
z;r3f*GWOwd@`Rxvt3^IPniT+4B2D*iP1FzuJOv>0I_yLIggSXz0cG-$FjPkoh4@8r
zI)gj`0D>C(kp-$Dj71H`;$u9YEvMQqUEai>)JFn7#&4*JA35SU+TK{4JXVk*)||_V
zMZe9@F@5yQg2&gL?ulCcLWM`nZ(RDt@18utc9CpfFMYTqG>WB^Ja~XASui5Il8oD4
zy5~3U@EQp+D*HSKg;ezQ>fv9wDB{*QIWWJeY3RTj?o#8!Nkwvj)}OF
zHoe8xFnXIaYCUMnGRNufehLy;O^K#8M^3$WRFLTKjYN?bMHX-g7L-kv%Id#Z13MGc3x
zDswa)=NK{mn{-fP>DnKu0N(mi`hOUeoSmh+|78qK(Z7swIv3Bg@G3?m9tx5{g(o=L
zdr1C^c45!L&Y9zH>@in3-id_2qd`B!m%NH;@a*cH5UogtD$$(4-=ndG`$`y%Ta!&E
zTTi|+vHa(%qW2nXix87<;=S6aA2+?sHj_EF1Xu44D=qDRYDo
z_?L;c%^E5_iUyhd0lsW?hbC14DhuP6kB%_3&?i@QN=rkK1*qjvx6L5ai?t`xp9*#Z;a@;O#&6t2fN(8-D~7
zKZn1ZkQu2q?CsDwoi}F_I8((
zu5MkiYhXWzs6sqRv8>`_jZOfTwZLrfS#D+F_=x0c3MWheURRSc`%J_6M2+hfy!csW
zVyR7e-GNNDjMt#vLJxu6_<>u%$eh?>88|=}fe$EW^+RKaBRQ8-UU-Hs4sNI=V?-)4
zv7@rR5NEZ^qpG8_XUhRxF&@Y#to=Kc#Hh4gM17bwu;y`YxFc3kYwJXc`K31CzA~vB
zf54N07%Tc^!C$0^1RE&Yx+@Iva7dm~?A&3GWZYJC}
z52|@rObF7;)prh}9blZBUoLKF^jqI(e;fJN(uMq*`Sy&OS`Ba0@x_LKn{w$(=K9O&
z&I3e~)Q$9lh&lX{=gstr_LjxXdD4cF)AI7>=D?!K`3vbna~iwz8?NT2&ZC=fdLeH(!FnCbnRrNeSS;1Z)3d@hJ@K6j@MQqrt=qxX=}v;
z(;HW`c;(CG0>;ujciZ=go-skA6Zx^D$zS#ZgCZk#dgk`mS*a%5V`a^Uhsyf|c4W;r
zlNQiBOGW{*W3t#2OCG$2vfR(x^R#4M$F`H^RKD8#jRr*Lw+E#dNGdlhVM60$ZcBjPXY)MbSX%MG)S63!Gy;=}aXsHt%l>Sn
z#pckvVUg&@Ei~$VML3!!Mb@uK>%4wxOxniourg#IHiEI#TR`7bE=|r{+ac0vsidGg
ziE$J^6~tFN+@0sH#oJous4#R0StUB3(ZGDac*z+pzb9+ETeLG(k|V9j
zGCsVrx$O4QfNo&lXH#wNVdM_dVKa<4z3pC=3M*kO-i{ZJneq4aX{*|mRCQDxWh8vc
zhwZWJe%ZipxQt=Xh;px#-{&naKG+*KkL&29HhB;y7{e=(mOQ7Zx#NFhyYp6{6&Kf3
z%T#i<%JRPF=BTU$5!cD5nN)K)y}fq3=wW^(H)Cn@nqJB7*W-+96g%S{lAnUI7%TUa
z6yrFL>3s^ak(
z<8PixLWI@n%FdLx-{x}nXFP|^@z;IMgyd*1(CCreU-70VJv3wyX7AZ`*mk)Az5eJx
zQL(bow61Ik@3gnG&ht&%Q+xkpYTS_b_M4xdA6?k-mwxWeHFGs~O~<9GRnz>Wq}s!P
zoo@^L)F{
z{tTu5ou9g4NjpQ@JojG0Xp{td)YH2{tNArOJy)EA&Q()MK@c@xzP6YvxH(*F^_p3g
zzwqVjc`1p=cS;phoc5WFCI_3uMDgj>VNGKbY*yNV_x@VV
zwug8y&q2(WdHQbQC;Io&AKv3$7Pb@*{!FPM)UFQ_ur#2LP)J^lGtR2-4Fru6zP9|}
za1wsENOL1wllMk6^kmXvQ_FavbEo^~${k-XQjW82Tk*x$Ue=5xhOLCh9quD_5iAY*
z&A|{&T46`t@~294m=&I@w?dn~*WGN9S05C}c(SgbQPhe&5GMuh?HgSP6FRy1eLqI$
zj->xL`G!d5!T#cntc380$lG`G_-8k*gm$<~YV=--3CA4RRj~zrsbeXe4>0^@)FTu{
zm+ujN(?8w6@i=0wpyagNNiH4A_9w5B1ufgmQgj^CPBY!r|KK=qaLktK#Jz#LKfZkK
z!hF=KLHaZ_AAi`Z!JmB`j2~}(GVL7kB_kp^Hu2P*dF|#WNM#~{K#xiKBGDa1+j74l
z^Gqt;9myA_$1lIBCbp}aX+7wWa(feYP0{efd4&j!v^A67)AQQNGX)<`Jy%PedbN!X
z=}%Xp++k(8AB)K;^)^|zA|;5ZXP--58SY`dFHd92KcLe;1?QK|8UA)I3-4ev*ed8O
zt?ij<90?-}-~oDdWVzHrXvxr)&DhIjAc@BVeei7p;&Sv_xl;sV@@
z8@jR9>URU;-CVCh%{D(WEFl!H*Y9!dRjh-uXSQcZnX9Wx`j{+~d&*YwGecbOg-REQ
z9s$~u?YWBkFc91s_RToW?d}abbw$3rn*5Zm*U)z%w7Vr|Cn}fka+_n$T-`IHoO^VY=;r+Uo1V^A*joecjH9s~+6#$SHI6IZh<*b!&etB6W*r13xW*n++w;a=
zRKN>P#H}9xkCaH}a}wut!RIfqhwg?;?-IG@LPfa3j@2d@W?5{NmkN)nu9LpqlslXX
zRm|i*+;g!zCBe~CWO$F?(l3m!?FOStCu&2xV=YBKBki0!Uqx8Ubd=Ap
z)Qq^dzB<>b7}#GJX*KSi`IxI*cOX(n7WNJT!o(>-&U6w~3bSYV<5MLl!*0f?e)!gT
z-PEZzU^+*CD^CG@Pu0Bz8Y6a9rO(Z%Sn`hBi}-AsH2$n_7&@N|6&|_MvSQ0pQuhm>
zDFLXZM=yO7^6!N5S9G~0nR(g9**uRN;~0+k%MX^vvLbU$*rB}k_UAXxLcnD={lhYU
zf+j^*ltO~2>=m_b)px!;4Z5sPiRf0gBj#IQ4>ZUqR~<}`)KK^l!9t}b9{BM-T+_v{
z$J3E9PPPYkisKz4n}NyP*H+~?&{bx;ZOfb8;!7%Z9gn=Wl(=0DE-k*mMC&zSXGYJw
zMn+Pe6PsLD4Zftp=BoXvfXy__jPRN#cv6k`>-}06+az96Vbbjy$7fmx`vn&=l64;J
z9<=Yg5On2AH@1b0mX_Co-ox{gO>HTs>-ib#r>&hKQ4UDUG2vsw`zm=Zp
zEy7YRw=;StYn)qaj2cmMli0|Zy>n$^$hHo0_q(&uXlJ7H-LGm99fxW^YvfTx1kBXg
zlait
zCfmFXqDu`GByZ+Iyvni~V*`&{LYD3RbK2efA56Pj|2L-H|7pnm`8`t6|MiEVA-Dcp
zBM$=kkC7Lq4|N-rV5;BMcl3Dm@QPl%wc$Lp0;Mhr&D8suebW3Q^ZOSs9#g*X++W^h
zeWN@N8&l!yepG7iJSp@gU0)<-aIXF-ks$m
z`0f2$54@uI6NG1{q;SdG%dGF8W+~nq`im~Iovz9uq3QZT%x9u_O%c`ddlt)^9Azja
z4*K@JzK4=;sRljnvSZsnS===Gu-Vj0S7ccf)xP@joq&QA$p&n+EMe9q{b<#WQaYHx
zKNojwJo7K3@x||tZ=28+E!ob}RZl&>V_|ylhFy1FMU4d{bxY0FMT@R{JiE^|6LQ`L
z^g7y~#RXDKSh%Byy-pbFX))0L3@9$k0Nt%W-H(96qiq7l@=7{D>Sfz!yCpE(8Gkvw
zI!ILxR8Fl~zpYNLVWBfnSXmG(3j
zHR3C+2ekYQ>gb<}ysx5p1v~X&L7Gb0r{u3lhoN)cdEM1AE2;ZdVGSJgEl=1?V(@l!Ji?{Ss-UHPlHpa&Q=75kbXlOh_@
zUjr2FYNt+^2+K_h5*3Y3igDh%EdC7kgFreB=1={m%U`{-{{Iwro>5J9+oDE95D*Zg
ziHHbDQy`7x4Imwn-ld}u2)#vmkuFG)8bIj?h;*b^r5B|O(u;KI(h=n1-uLV?KEt^8
z+h?3H_WLhSR-1FJIcJi!R_0<2VeH#yc(&?(U!7Zq*1|ecjn?T4&$naEu4A_22eFA%xdkiBZlVF3hwMWDVtg^(U%T&7a?U+98Ejkzq@PeE_`YI}
zHLuc0iT`W!{ul;<6EydeU6vD2MnHe(*2jmvt84V;9s&BwY*kV5>G(yQJgi6A9k0ZF
z5sJx1?UeCKb!^gJZq(D4$-#uL+zRrh*HzI97xwl@8jw5WDiN>RKCI{QHIbR=ViUvG
zA$x2N??{l6S2SrtX(>WVhlX!gH<=ekmT+8_m+L0VHsk7>Qri(aUAgV}MR4vzSt@eX
z{i53h*WBgj-{g|2IQ+9^)l%#IJ3=&Wdosx9jK0WS8Okg3-gjt)fexP@-bwEwKcrDz
zQrrmbp7Q8sT)}(0BYMeJm@yD|c@l3WisQo;zeB~%D`BF4}R;Wq=q
zmWe+^@3PsectF%>Z%EW$#*)e_%em{KIwVCDQr`*sy}G8oWNRZSFdnS8j|93&U57PNs{DTRgWhhzc1Vo3#N*(o5-C{GI0m`Cpj*u
zsWquNZO#$j-ZRR@Q1eaLu2O7FKfgNR?oPjrx_)amNbC9V7ds9+G94XaWt9Hferv2W
z`|Q(bqTSE#p4u08E~!PU
zU&09XSUJrUX^gkLK~*fa2_HCr-YPyk1lJ1keyapTjykN&TWpC}b&}fc5^s&9X}%ft
z{Q!e|6i)gi!kwV`)rAK5Ldg*
z(ps2_I!+9zxajFQ(;zm#%j01ijDNU!EyuO7?}*Hp+hXAoU(;A$V>rE6lA`x7Bg)rb
z0#5h41|MslUN{P|5yc6W0O;?BN&x(y2$lZ|jsW;?{aH60H#lM+DcFtySL+rvuXv0&
zQ06+l7FY-0BGXA7b2B8GxP(cQ8bz~4a?6bD{yOrMkPUugUB`n7x*Z9%opgu3Dda#g
z%-G7uE$&!|ySifP09RLMu~{(BBNyl^gMRUT&KqG5O52s5T0U~q7nH&duyZcT6mnWo
z%ajdPvG8Dt-7=q2mhxwGbymMWT$8a1;B9`dY|0iYd1c;SXtJ;lQ#xQM;Y+f1abz&0
zB`%thtgZ0jAHQSHVXZJsZ1w8A`
z`W4$(Tfn^{?ktr2T?1JWV3%q^0txnw{aiZX`{+gU!{wDs&BvBm`Bb;3N{3l?;+$wRJrr~lodp4z?O#nfxh!X51M@(w<*e1Ze1c>21YdvDrHCnL@vB^PB*
zFIpNz`dkY4-1UhZY<5VmAL&-WKKv^S=g6m96K@FsYll!yOneBXE%vES<77u>6^~pk
z6Yc1cQDOI~=Ddy%w1
zu)eG$N3(m5L<#9P%ftvNJLX8%Me0v;1-EYgM3)Yy7CB%iY@P^?%n^6NWFX-TuarW#
z31fN&MXYZ+eSS!1#rF2clZoVo&KBbRYo0u8>V}-}Yt{y=-GG~=>yHI$P}6>abfu~+
zA9W*-RE2V~GUzEKjnIZg9+gK+Ri{l+1Vc
z9Ydz=Jni_5h76xA_3F?Q_jQ-5F}CgZ<6GMaP?#Tk@v%{hlNP^8?Q441Idol`$*Nb~
zkC3AEMd_W;pj)D7b?=?<yCrwu$@c>jFg+Z&OA@nc1hl>aD&s2z51_l`b$;B9^EVVJf&)~BkI)S?tmd$n5IJjlAM!e0A@&R11ABKv
zAHQa_KL4#N@vYchgKeV<$L#Mrj$2lzjjZ`Cqo2gTtq^^xiL22?yJ#;Jg%=NzB-}#j
z2cLk3Z~t2^p%VD8Xg>Agj{c&s``PO=sH*dlmYA
zIc8Sx`cdh;55?y$bWKCK59zFLLYZ;*Z0NLE6TE#Bv$Jr3m~V+0(DUYHvOAtz`!?4T
z?R8;4fcOS(DET+CL;%qLY$*9#c^~*e;B!LBC(Ia}dgABZb>sQZ4@>6)?`?b^c5F?8
zsYqiIq~OfNvO!|rw?*%Ee%;se{^I8}?y!1E3V+|eyNc+*36@3qtJMKMbDAgQRsjf9
z3BKKmr@d4!pA}cyZXOf*fK|u1Ed-nK%JEt9V9pP9&NUN-&d6d**??%|NP6o2ty@bc
zBrAG)&XIbdRNuND6x8TzSf{A--oz@Dr>ncwdej`a!O~|A?jfZnXJv;1^5qO6GM4k2
zrK+E>d4XjPj}Qjhew>|8-mn^CFbWzYqpWP00ir`T{-ia!yZ~*u5!btjM#Sal((6hb
z9Z1tvi^Pe^HOGpT&$Bhh$ujwwTRT;qq?qzeOBGhMwOlo}%p)Uw=ymD4xIm2;tz)V#
z*xj+YU_JIy$R|_K?YdNPK!~Cpi~nj%S%)nz^AXG7v9ft&N0cT0leA7@qNVIOIJ>A~
z9$oTKqe_z}w*-Qs1Q{0H*E7BK<7cdA*0V9A9E`@N(07yqyr|0%!-uh4zH~z%D&^3a
zs?QR>(KUC2rHU7xza21c>?okBPU$jZLbU}5nqw3Ol)vPab3GaMFE1ld-^oZcdg8*G
z+e}-0$Gam0u+qi!?+UPMJQ8>kbX2-=DXB^uBXTep2u$m`|Jk?ZSJB-)8)8AL;72NgR}x7
z<94q(T($+Vkvw?lJ^MvRWLhkwz9=b(=>j>5C=J_Lg$GqS?m^EpZEfp;^)HUn-sHrT
z7L&Qkg{wYF^Dy!4yHwnoqXjuO3DADQ9w*)RF;tzASSymH%vD%xfmZLi4YEv!
zl|LR_0@5f-bgTP@voCzF)-OEnt`>A$}k#}gky+kloc`2wPQ
zPrxh|`H^RlwmARmvjo;r#XE`74c}$I<-_e%NdWiM>}O?t1O7}!RxWo*O_WEhPJ>RU
z?|nLHbm5L(evYl!xJ*XWJ@%2v)OkmoXoc2#KaiGSwwP~z@<^#)Vs2($o!&;XL!Njj
zVcVm^E=ekcBh3L&saW~I_=zC!N5Wo_@c~1#;!AvRCd(}E=kx?
z*z6(O<2pu+J97(VbZ?QzVzaqBwtcLZOh~=hr$frOiU~MPN@^A!vAAF1ctD>CjOnW`
z+<$nS`Kz(+a?~v9U0KHAZpuc1y#lq#RRc?E#&^~RMKaHqjbkE}&GfK8x+b$5zlg^h
zbgCt`M_=_%;Z@PjaFD3(V3Kgsx~P|`3W;8mO2gh%Z>wNs=LOYSX;b6`@fXsN=apiA
zluEe@C9^MTqF(DIb405&kM?rJH$?lUmGM6H8<8jq4Bt=wLgD%0k1poA)
z1v%;zw8U$=`tgW`!|U$obmNey=m=xYL^iMD4A+iVGa0e48(!56M2p)SNfFg2)VrTU
zN)C1U-k^77=kg>o=G{6lHfAl!$l~e+`E6hIg#I}_j1X9kEXrU?!L<2GzNu=e&5of46
z$c)Y#3uJzWnzk~r_8eKc&tFCyYT?iwxe`efH3qk7)Bf7#^9|VRRoS?&z;AK&M`V`#
zk0_?@$qA*m8%*6^-rs0cc6oF5R8DIScHM4%$yMlmcmWN6jc}r&t~Hg?-ZS`Kz0V%i
zqtH@jafK@=!<D)(dHy?Nl1)hN_HUnh4h^0o|ngvEkyvNNYO0
z!*)JJm{9XEe)G6FfxTPiC$i?5b41NUkJn042q
zwVhF){n25XVIO#Fm(SPke8y&hhP_YyhRtxoP4&U;5fzCW0_kRWpN7RknwW36nLV~B
zc(su_(yC=}y&AgSl?E&{ldXV)20jPMh;+UTm%emAjm<8`vK*YB%sd^bi-@6#zESVoEguWU*CE_V<|E*wT=0*o?Rzb!Yg2yABn7qB*Jxyb
z4DC0sH1P`c)hCvVgx|HtUvTk8kDAcX7T93~8vTVKuxp7_p=)5q;hNFBcidSB+pEjZ
zPjxhC7$)rI
zzMs;^OZTcamQJ?DF!hH)cMDSRye`(~FubjjcOfW~qPyle+FCfyXx)%$E;MMJ%^5J!
zt20cK#y%Ta_nflyN3~!WO-p$a+v9;KXo#e4B8_`v07|J#jLK`l=KVd{RFBN&*n;~Z
z@u11~`&m(5g)w)3>BxM-{Cu8@cxb@2W+RfQ=6bceTPV1?j$j*38h^TM7oLxev))|0
zJwuM3E0+iDz{a=;CAeRYzkb6bLv@ETETDkq!CV5K=SC7wUmj)b?2*#T^3!+IPL`R$
zq(}aHJV^^DpfI&fpPSAlTkCs!_fBaqfuD&sHv#mShAyQGiRCNV2cC;nBH)Zdj}GvR
zS*#Q4h&9TVBbr#UdlR*wMG|Mp@vGdVP3lfY!p@^$US2J`2tB3;YkR#Z6s7@axu15E
zSzYDkCC?&4S!4sXBU*$HwfgCXk4oN9#iFK|P;q4AXkj^L`j@{#cG<5#?4V+9TS)tf
zhHM-U9@4ck(lz1w;eX@s0`R|Zc;SEUe)<2JvK9C{Cm7%m7&Gp6j+%n)sOWF^yAc1d
zc$U94eljWs_At${>B0BgaryTN5G(r5&OSdj1T9ff*}-?Ox(FXndek1?H@eyv*Z}NK
zr87wxN+u8VG|_GNz~q)Io*Ofur6n43NEOhAvT62`UP<;OQe2r|Kh~B&k9yfc8k;Y+
z&aH;3nMFD1S!eSrrn!t_9Mgt2(=3InYZZLJ)0Uepiav4HCzPAttiX#E4JP_ICH786{T#IXNkW4#RG~8M5u!4t*5nqC-;i7ZtsuXYz=$Ec0%u5
zg)Ois&+4O{VN1=-X8U}S#gpIOI52`KP83O!;0?W4|25^w3zIwEw-`!KXOu?pPH$eI
zmrlpG@qcgmy}*{#7jGTtdE6p+5uO&kEYo@~G}`IHgBUH+ZKJ7cQdfH&!v^xE`ojuN
zrkOtQKC5Nw$kFeu(}%BZ>H_cYUL>^kb6^rwT{1{3HvFpPWEEO`Pab{cn*$ZQijz>k
ztstz1WdCHB%wc85m+4OY11LqLt1Xr344`Q4bb7_9TY5^`>w*sL^B`P{`(p!D!qCCc
z%GUIs*(LwW=6=7BH*~dibl_7nw=uOc`M-8)YNGIad22j1QM9!&`Ij-cU`)^?AZ7r`
zOal7X!wl!=hw?L{|C{~J(D;vcZ2rX{P#gvZ&c2)DFa&NnX&
z3~~;Gp2J}0F#dBG{2X?U9Q^0V!GDe%@N?vVgMX(-|C1qcbP9*y&IcR{!(}iiZe7?p
z?eU+}9{l$w@;?{?!jH=UFb)IYxN;!D2wa9+7XiXuR|qifnnXarAY29jI1Gxw?E?nI
zZSNlmZ~tTfjvNR$97k6O1dg49&(wlD765_U9ukCG4vDLK;GA^;;QE&{hT8`K#nn9k
z)=eKxN-ovb9AQWKifO=
z2Dl6g2L9{=3LtR&GZaAb|H)t=ejFQwfe<)02!lWYT*i;v-r02EFc=uewqX1SoH>H=
zBXRphfcbIio(=EMxr6~{;{7*sz!;ianP5nMXKXijGdYWce5$s#4$QzmGk(k1plzA|
z8CPW_b%j7srequest.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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs);
+
+ 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 url[HTTP_MAX_URI]; /* New URL */
+
+
+ cgiSetVariable("DEFAULT_URI",
+ cgiRewriteURL(attr->values[0].string.text,
+ url, sizeof(url), NULL));
+ }
+
+ 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;
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
+ "printer-type", 0);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
+ "printer-type-mask", CUPS_PRINTER_CLASS);
+
+ if (getenv("REMOTE_USER") != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, getenv("REMOTE_USER"));
+ }
+ 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;
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+ }
+
+ cgiGetAttributes(request, "printers.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Got the result; set the CGI variables and check the status of a
+ * single-queue request...
+ */
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ if (printer && (attr = ippFindAttribute(response, "printer-state",
+ IPP_TAG_ENUM)) != NULL &&
+ attr->values[0].integer == IPP_PRINTER_PROCESSING)
+ {
+ /*
+ * Printer is processing - automatically refresh the page until we
+ * are done printing...
+ */
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "10;/printers/%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+ }
+
+ /*
+ * Delete the response...
+ */
+
+ ippDelete(response);
+ }
+ else if (printer)
+ fprintf(stderr, "ERROR: Get-Printer-Attributes request failed - %s (%x)\n",
+ ippErrorString(cupsLastError()), cupsLastError());
+ else
+ fprintf(stderr, "ERROR: CUPS-Get-Printers request failed - %s (%x)\n",
+ ippErrorString(cupsLastError()), cupsLastError());
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiCopyTemplateLang("header.tmpl");
+
+ /*
+ * Write the report...
+ */
+
+ cgiCopyTemplateLang("printers.tmpl");
+
+ /*
+ * 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;
+
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/printers/%s", 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);
+
+ if (getenv("REMOTE_USER") != NULL)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, getenv("REMOTE_USER"));
+
+ if (strcmp(getenv("REMOTE_USER"), "root"))
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, "unknown");
+
+ cgiGetAttributes(request, "jobs.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+
+ cgiCopyTemplateLang("jobs.tmpl");
+ }
+ else
+ fprintf(stderr, "ERROR: Get-Jobs request failed - %s (%x)\n",
+ ippErrorString(cupsLastError()), cupsLastError());
+ }
+ }
+ else
+ {
+ /*
+ * Print a test page...
+ */
+
+ char filename[1024]; /* Test page filename */
+ const char *datadir; /* CUPS_DATADIR env var */
+
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "2;/printers/%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir);
+ httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
+ "/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,
+ filename)) != NULL)
+ {
+ status = response->request.status.status_code;
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+ else
+ status = cupsLastError();
+
+ cgiSetVariable("PRINTER_NAME", printer);
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiCopyTemplateLang("header.tmpl");
+
+ /*
+ * Show the result...
+ */
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ cgiCopyTemplateLang("test-page.tmpl");
+ }
+
+ cgiCopyTemplateLang("trailer.tmpl");
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+ cupsLangFree(language);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: printers.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/search.c b/cgi-bin/search.c
new file mode 100644
index 000000000..4f1ea072a
--- /dev/null
+++ b/cgi-bin/search.c
@@ -0,0 +1,368 @@
+/*
+ * "$Id: search.c 4859 2005-11-30 23:45:24Z mike $"
+ *
+ * Search routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * cgiCompileSearch() - Compile a search string.
+ * cgiDoSearch() - Do a search of some text.
+ * cgiFreeSearch() - Free a compiled search context.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+#include
+
+
+/*
+ * 'cgiCompileSearch()' - Compile a search string.
+ */
+
+void * /* O - Search context */
+cgiCompileSearch(const char *query) /* I - Query string */
+{
+ regex_t *re; /* Regular expression */
+ char *s, /* Regular expression string */
+ *sptr, /* Pointer into RE string */
+ *sword; /* Pointer to start of word */
+ int slen; /* Allocated size of RE string */
+ const char *qptr, /* Pointer into query string */
+ *qend; /* End of current word */
+ const char *prefix; /* Prefix to add to next word */
+ int quoted; /* Word is quoted */
+ int wlen; /* Word length */
+ char *lword; /* Last word in query */
+
+
+ DEBUG_printf(("help_compile_search(query=\"%s\")\n", query ? query : "(nil)"));
+
+ /*
+ * Allocate a regular expression storage structure...
+ */
+
+ re = (regex_t *)calloc(1, sizeof(regex_t));
+
+ /*
+ * Allocate a buffer to hold the regular expression string, starting
+ * at 1024 bytes or 3 times the length of the query string, whichever
+ * is greater. We'll expand the string as needed...
+ */
+
+ slen = strlen(query) * 3;
+ if (slen < 1024)
+ slen = 1024;
+
+ s = (char *)malloc(slen);
+
+ /*
+ * Copy the query string to the regular expression, handling basic
+ * AND and OR logic...
+ */
+
+ prefix = ".*";
+ qptr = query;
+ sptr = s;
+ lword = NULL;
+
+ while (*qptr)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*qptr & 255))
+ qptr ++;
+
+ if (!*qptr)
+ break;
+
+ /*
+ * Find the end of the current word...
+ */
+
+ if (*qptr == '\"' || *qptr == '\'')
+ {
+ /*
+ * Scan quoted string...
+ */
+
+ quoted = *qptr ++;
+ for (qend = qptr; *qend && *qend != quoted; qend ++);
+
+ if (!*qend)
+ {
+ /*
+ * No closing quote, error out!
+ */
+
+ free(s);
+ free(re);
+
+ if (lword)
+ free(lword);
+
+ return (NULL);
+ }
+ }
+ else
+ {
+ /*
+ * Scan whitespace-delimited string...
+ */
+
+ quoted = 0;
+ for (qend = qptr + 1; *qend && !isspace(*qend); qend ++);
+ }
+
+ wlen = qend - qptr;
+
+ /*
+ * Look for logic words: AND, OR
+ */
+
+ if (wlen == 3 && !strncasecmp(qptr, "AND", 3))
+ {
+ /*
+ * Logical AND with the following text...
+ */
+
+ if (sptr > s)
+ prefix = ".*";
+
+ qptr = qend;
+ }
+ else if (wlen == 2 && !strncasecmp(qptr, "OR", 2))
+ {
+ /*
+ * Logical OR with the following text...
+ */
+
+ if (sptr > s)
+ prefix = ".*|.*";
+
+ qptr = qend;
+ }
+ else
+ {
+ /*
+ * Add a search word, making sure we have enough room for the
+ * string + RE overhead...
+ */
+
+ wlen = (sptr - s) + 4 * wlen + 2 * strlen(prefix) + 4;
+
+ if (wlen > slen)
+ {
+ /*
+ * Expand the RE string buffer...
+ */
+
+ char *temp; /* Temporary string pointer */
+
+
+ slen = wlen + 128;
+ temp = (char *)realloc(s, slen);
+ if (!temp)
+ {
+ free(s);
+ free(re);
+
+ if (lword)
+ free(lword);
+
+ return (NULL);
+ }
+
+ sptr = temp + (sptr - s);
+ s = temp;
+ }
+
+ /*
+ * Add the prefix string...
+ */
+
+ strcpy(sptr, prefix);
+ sptr += strlen(sptr);
+
+ /*
+ * Then quote the remaining word characters as needed for the
+ * RE...
+ */
+
+ sword = sptr;
+
+ while (qptr < qend)
+ {
+ /*
+ * Quote: ^ . [ $ ( ) | * + ? { \
+ */
+
+ if (strchr("^.[$()|*+?{\\", *qptr))
+ *sptr++ = '\\';
+
+ *sptr++ = *qptr++;
+ }
+
+ /*
+ * For "word1 AND word2", add reciprocal "word2 AND word1"...
+ */
+
+ if (!strcmp(prefix, ".*") && lword)
+ {
+ char *lword2; /* New "last word" */
+
+
+ lword2 = strdup(sword);
+
+ strcpy(sptr, ".*|.*");
+ sptr += 5;
+
+ strcpy(sptr, lword2);
+ sptr += strlen(sptr);
+
+ strcpy(sptr, ".*");
+ sptr += 2;
+
+ strcpy(sptr, lword);
+ sptr += strlen(sptr);
+
+ free(lword);
+ lword = lword2;
+ }
+ else
+ {
+ if (lword)
+ free(lword);
+
+ lword = strdup(sword);
+ }
+
+ prefix = ".*|.*";
+ }
+
+ /*
+ * Advance to the next string...
+ */
+
+ if (quoted)
+ qptr ++;
+ }
+
+ if (lword)
+ free(lword);
+
+ if (sptr > s)
+ strcpy(sptr, ".*");
+ else
+ {
+ /*
+ * No query data, return NULL...
+ */
+
+ free(s);
+ free(re);
+
+ return (NULL);
+ }
+
+ /*
+ * Compile the regular expression...
+ */
+
+ DEBUG_printf((" s=\"%s\"\n", s));
+
+ if (regcomp(re, s, REG_EXTENDED | REG_ICASE))
+ {
+ free(re);
+ free(s);
+
+ return (NULL);
+ }
+
+ /*
+ * Free the RE string and return the new regular expression we compiled...
+ */
+
+ free(s);
+
+ return ((void *)re);
+}
+
+
+/*
+ * 'cgiDoSearch()' - Do a search of some text.
+ */
+
+int /* O - Number of matches */
+cgiDoSearch(void *search, /* I - Search context */
+ const char *text) /* I - Text to search */
+{
+ int i; /* Looping var */
+ regmatch_t matches[100]; /* RE matches */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!search || !text)
+ return (0);
+
+ /*
+ * Do a lookup...
+ */
+
+ if (!regexec((regex_t *)search, text, sizeof(matches) / sizeof(matches[0]),
+ matches, 0))
+ {
+ /*
+ * Figure out the number of matches in the string...
+ */
+
+ for (i = 0; i < (int)(sizeof(matches) / sizeof(matches[0])); i ++)
+ if (matches[i].rm_so < 0)
+ break;
+
+ return (i);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'cgiFreeSearch()' - Free a compiled search context.
+ */
+
+void
+cgiFreeSearch(void *search) /* I - Search context */
+{
+ regfree((regex_t *)search);
+}
+
+
+/*
+ * End of "$Id: search.c 4859 2005-11-30 23:45:24Z mike $".
+ */
diff --git a/cgi-bin/template.c b/cgi-bin/template.c
new file mode 100644
index 000000000..dfcd1b85e
--- /dev/null
+++ b/cgi-bin/template.c
@@ -0,0 +1,573 @@
+/*
+ * "$Id: template.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * CGI template function.
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * cgiCopyTemplateFile() - Copy a template file and replace all the
+ * '{variable}' strings with the variable value.
+ * cgiCopyTemplateLang() - Copy a template file using a language...
+ * cgiGetTemplateDir() - Get the templates directory...
+ * cgiSetServerVersion() - Set the server name and CUPS version...
+ * cgi_copy() - Copy the template file, substituting as needed...
+ * cgi_puts() - Put a string to the output file, quoting as
+ * needed...
+ */
+
+#include "cgi-private.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(const char *tmpl) /* I - Base filename */
+{
+ int i; /* Looping var */
+ char filename[1024], /* Filename */
+ locale[16]; /* Locale name */
+ const char *directory, /* Directory for templates */
+ *lang; /* Language */
+ FILE *in; /* Input file */
+
+
+ /*
+ * Convert the language to a locale name...
+ */
+
+ if ((lang = getenv("LANG")) != NULL)
+ {
+ for (i = 0; lang[i] && i < 15; i ++)
+ if (isalnum(lang[i] & 255))
+ 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...
+ */
+
+ directory = cgiGetTemplateDir();
+
+ 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(stdout, in, 0, 0);
+
+ /*
+ * Close the template file and return...
+ */
+
+ fclose(in);
+}
+
+
+/*
+ * 'cgiGetTemplateDir()' - Get the templates directory...
+ */
+
+char * /* O - Template directory */
+cgiGetTemplateDir(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);
+}
+
+
+/*
+ * 'cgiSetServerVersion()' - Set the server name and CUPS version...
+ */
+
+void
+cgiSetServerVersion(void)
+{
+ cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME"));
+ cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER"));
+ cgiSetVariable("CUPS_VERSION", CUPS_SVERSION);
+
+#ifdef LC_TIME
+ setlocale(LC_TIME, "");
+#endif /* LC_TIME */
+}
+
+
+/*
+ * '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 & 255))
+ {
+ 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] & 255))
+ {
+ *nameptr++ = '\0';
+
+ if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
+ outptr = value;
+ else
+ {
+ outval[0] = '\0';
+ outptr = outval;
+ }
+ }
+ else 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] & 255))
+ 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] & 255))
+ {
+ *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 && outptr[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] & 255))
+ {
+ *innerptr++ = '\0';
+ if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
+ *s = '\0';
+ else
+ strlcpy(s, innerval, sizeof(compare) - (s - compare));
+ }
+ else if (innername[0] == '?')
+ {
+ if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
+ *s = '\0';
+ else
+ strlcpy(s, innerval, sizeof(compare) - (s - compare));
+ }
+ else if ((innerval = cgiGetArray(innername, element)) == NULL)
+ snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
+ else
+ strlcpy(s, innerval, sizeof(compare) - (s - compare));
+
+ 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, /* I - String to output */
+ FILE *out) /* I - Output file */
+{
+ while (*s)
+ {
+ if (*s == '<')
+ {
+ /*
+ * Pass and , otherwise quote it...
+ */
+
+ if (!strncasecmp(s, "", out);
+ }
+ else if (!strncasecmp(s, "", 4))
+ {
+ fputs("", out);
+ s += 3;
+ }
+ else
+ fputs("<", out);
+ }
+ else if (*s == '>')
+ fputs(">", out);
+ else if (*s == '\"')
+ fputs(""", out);
+ else if (*s == '&')
+ fputs("&", out);
+ else
+ putc(*s, out);
+
+ s ++;
+ }
+}
+
+
+/*
+ * End of "$Id: template.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cgi-bin/testcgi.c b/cgi-bin/testcgi.c
new file mode 100644
index 000000000..e9300af87
--- /dev/null
+++ b/cgi-bin/testcgi.c
@@ -0,0 +1,84 @@
+/*
+ * "$Id: testcgi.c 4869 2005-12-06 02:43:40Z mike $"
+ *
+ * CGI test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Test the help index code.
+ * list_nodes() - List nodes in an array...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+
+
+/*
+ * 'main()' - Test the CGI code.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ /*
+ * Test file upload/multi-part submissions...
+ */
+
+ freopen("multipart.dat", "rb", stdin);
+
+ putenv("CONTENT_TYPE=multipart/form-data; "
+ "boundary=---------------------------1977426492562745908748943111");
+ putenv("REQUEST_METHOD=POST");
+
+ printf("cgiInitialize: ");
+ if (cgiInitialize())
+ {
+ const cgi_file_t *file; /* Upload file */
+
+ if ((file = cgiGetFile()) != NULL)
+ {
+ puts("PASS");
+ printf(" tempfile=\"%s\"\n", file->tempfile);
+ printf(" name=\"%s\"\n", file->name);
+ printf(" filename=\"%s\"\n", file->filename);
+ printf(" mimetype=\"%s\"\n", file->mimetype);
+ }
+ else
+ puts("FAIL (no file!)");
+ }
+ else
+ puts("FAIL (init)");
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: testcgi.c 4869 2005-12-06 02:43:40Z mike $".
+ */
diff --git a/cgi-bin/testhi.c b/cgi-bin/testhi.c
new file mode 100644
index 000000000..99d0bd29f
--- /dev/null
+++ b/cgi-bin/testhi.c
@@ -0,0 +1,116 @@
+/*
+ * "$Id: testhi.c 4869 2005-12-06 02:43:40Z mike $"
+ *
+ * Help index test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Test the help index code.
+ * list_nodes() - List nodes in an array...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void list_nodes(const char *title, int num_nodes, help_node_t **nodes);
+
+
+/*
+ * 'main()' - Test the help index code.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ help_index_t *hi, /* Help index */
+ *search; /* Search index */
+
+
+ /*
+ * Load the help index...
+ */
+
+ hi = helpLoadIndex("testhi.index", ".");
+
+ list_nodes("nodes", hi->num_nodes, hi->nodes);
+ list_nodes("sorted", hi->num_nodes, hi->sorted);
+
+ /*
+ * Do any searches...
+ */
+
+ if (argc > 1)
+ {
+ search = helpSearchIndex(hi, argv[1], NULL, argv[2]);
+
+ if (search)
+ {
+ list_nodes(argv[1], search->num_nodes, search->sorted);
+ helpDeleteIndex(search);
+ }
+ else
+ printf("%s (0 nodes)\n", argv[1]);
+ }
+
+ helpDeleteIndex(hi);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'list_nodes()' - List nodes in an array...
+ */
+
+static void
+list_nodes(const char *title, /* I - Title string */
+ int num_nodes, /* I - Number of nodes */
+ help_node_t **nodes) /* I - Nodes */
+{
+ int i; /* Looping var */
+
+
+ printf("%s (%d nodes):\n", title, num_nodes);
+ for (i = 0; i < num_nodes; i ++)
+ if (nodes[i]->anchor)
+ printf(" %d: %s#%s \"%s\"\n", i, nodes[i]->filename, nodes[i]->anchor,
+ nodes[i]->text);
+ else
+ printf(" %d: %s \"%s\"\n", i, nodes[i]->filename, nodes[i]->text);
+}
+
+
+/*
+ * End of "$Id: testhi.c 4869 2005-12-06 02:43:40Z mike $".
+ */
diff --git a/cgi-bin/testhi.html b/cgi-bin/testhi.html
new file mode 100644
index 000000000..747b5ea31
--- /dev/null
+++ b/cgi-bin/testhi.html
@@ -0,0 +1,29 @@
+
+
+ Test File for Help Index Code
+
+
+
+This is a test file for the help index code. The help index
+code reads plain HTML and indexes the title and any anchored
+text, ignoring all other markup. Anchor tags must be on a single
+line, although the text they wrap may cross multiple lines and be
+up to 1024 bytes in length.
+
+
+
+This is some text for the first anchor.
+
+
+
+
+This is some text for the first anchor.
+
+
+
+
+This is some text for the third anchor. This
+is an in-line anchor that crosses a line.
+
+
+
diff --git a/cgi-bin/var.c b/cgi-bin/var.c
new file mode 100644
index 000000000..4a1a214a7
--- /dev/null
+++ b/cgi-bin/var.c
@@ -0,0 +1,1024 @@
+/*
+ * "$Id: var.c 4869 2005-12-06 02:43:40Z mike $"
+ *
+ * CGI form variable and array functions.
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * cgiCheckVariables() - Check for the presence of "required" variables.
+ * cgiGetArray() - Get an element from a form array...
+ * cgiGetFile() - Get the file (if any) that was submitted in the form.
+ * cgiGetSize() - Get the size of a form array value.
+ * cgiGetVariable() - Get a CGI variable from the database...
+ * cgiInitialize() - Initialize the CGI variable "database"...
+ * cgiIsPOST() - Determine whether this page was POSTed.
+ * cgiSetArray() - Set array element N to the specified string.
+ * cgiSetSize() - Set the array size.
+ * 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_multipart() - Initialize variables and file using the POST method.
+ * cgi_initialize_post() - Initialize variables using the POST method.
+ * cgi_initialize_string() - Initialize form variables from a string.
+ * cgi_passwd() - Catch authentication requests and notify the server.
+ * cgi_sort_variables() - Sort all form variables for faster lookup.
+ * cgi_unlink_file() - Remove the uploaded form.
+ */
+
+/*#define DEBUG*/
+#include "cgi-private.h"
+#include
+
+
+/*
+ * Data structure to hold all the CGI form variables and arrays...
+ */
+
+typedef struct /**** Form variable structure ****/
+{
+ const char *name; /* Name of variable */
+ int nvalues, /* Number of values */
+ avalues; /* Number of values allocated */
+ const char **values; /* Value(s) of variable */
+} _cgi_var_t;
+
+
+/*
+ * Local globals...
+ */
+
+static int form_count = 0, /* Form variable count */
+ form_alloc = 0; /* Number of variables allocated */
+static _cgi_var_t *form_vars = NULL;
+ /* Form variables */
+static cgi_file_t *form_file = NULL;
+ /* Uploaded file */
+
+
+/*
+ * Local functions...
+ */
+
+static void cgi_add_variable(const char *name, int element,
+ const char *value);
+static int cgi_compare_variables(const _cgi_var_t *v1,
+ const _cgi_var_t *v2);
+static _cgi_var_t *cgi_find_variable(const char *name);
+static int cgi_initialize_get(void);
+static int cgi_initialize_multipart(const char *boundary);
+static int cgi_initialize_post(void);
+static int cgi_initialize_string(const char *data);
+static const char *cgi_passwd(const char *prompt);
+static void cgi_sort_variables(void);
+static void cgi_unlink_file(void);
+
+
+/*
+ * '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) */
+{
+ _cgi_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]);
+}
+
+
+/*
+ * 'cgiGetFile()' - Get the file (if any) that was submitted in the form.
+ */
+
+const cgi_file_t * /* O - Attached file or NULL */
+cgiGetFile(void)
+{
+ return (form_file);
+}
+
+
+/*
+ * 'cgiGetSize()' - Get the size of a form array value.
+ */
+
+int /* O - Number of elements */
+cgiGetSize(const char *name) /* I - Name of variable */
+{
+ _cgi_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 _cgi_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]);
+}
+
+
+/*
+ * 'cgiInitialize()' - Initialize the CGI variable "database"...
+ */
+
+int /* O - Non-zero if there was form data */
+cgiInitialize(void)
+{
+ const char *method; /* Form posting method */
+ const char *content_type; /* Content-Type of post data */
+
+
+ /*
+ * Setup a password callback for authentication...
+ */
+
+ cupsSetPasswordCB(cgi_passwd);
+
+#ifdef DEBUG
+ /*
+ * Disable output buffering to find bugs...
+ */
+
+ setbuf(stdout, NULL);
+ puts("Content-type: text/plain\n");
+#endif /* DEBUG */
+
+ /*
+ * Get the request method (GET or POST)...
+ */
+
+ method = getenv("REQUEST_METHOD");
+ content_type = getenv("CONTENT_TYPE");
+ if (!method)
+ return (0);
+
+ /*
+ * Grab form data from the corresponding location...
+ */
+
+ if (!strcasecmp(method, "GET"))
+ return (cgi_initialize_get());
+ else if (!strcasecmp(method, "POST") && content_type)
+ {
+ const char *boundary = strstr(content_type, "boundary=");
+
+ if (boundary)
+ boundary += 9;
+
+ if (content_type && !strncmp(content_type, "multipart/form-data; ", 21))
+ return (cgi_initialize_multipart(boundary));
+ else
+ return (cgi_initialize_post());
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'cgiIsPOST()' - Determine whether this page was POSTed.
+ */
+
+int /* O - 1 if POST, 0 if GET */
+cgiIsPOST(void)
+{
+ const char *method; /* REQUEST_METHOD environment variable */
+
+
+ if ((method = getenv("REQUEST_METHOD")) == NULL)
+ return (0);
+ else
+ return (!strcmp(method, "POST"));
+}
+
+
+/*
+ * '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 */
+ _cgi_var_t *var; /* Returned variable */
+
+
+ if (name == NULL || value == NULL || element < 0 || element > 100000)
+ 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 */
+ _cgi_var_t *var; /* Returned variable */
+
+
+ if (name == NULL || size < 0 || size > 100000)
+ 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 */
+ _cgi_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 */
+{
+ _cgi_var_t *var; /* New variable */
+
+
+ if (name == NULL || value == NULL || element < 0 || element > 100000)
+ 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(_cgi_var_t) * 16);
+ else
+ form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(_cgi_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 _cgi_var_t *v1, /* I - First variable */
+ const _cgi_var_t *v2) /* I - Second variable */
+{
+ return (strcasecmp(v1->name, v2->name));
+}
+
+
+/*
+ * 'cgi_find_variable()' - Find a variable...
+ */
+
+static _cgi_var_t * /* O - Variable pointer or NULL */
+cgi_find_variable(const char *name) /* I - Name of variable */
+{
+ _cgi_var_t key; /* Search key */
+
+
+ if (form_count < 1 || name == NULL)
+ return (NULL);
+
+ key.name = name;
+
+ return ((_cgi_var_t *)bsearch(&key, form_vars, form_count, sizeof(_cgi_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_multipart()' - Initialize variables and file using the POST method.
+ *
+ * TODO: Update to support files > 2GB.
+ */
+
+static int /* O - 1 if form data was read */
+cgi_initialize_multipart(
+ const char *boundary) /* I - Boundary string */
+{
+ char line[10240], /* MIME header line */
+ name[1024], /* Form variable name */
+ filename[1024], /* Form filename */
+ mimetype[1024], /* MIME media type */
+ bstring[256], /* Boundary string to look for */
+ *ptr, /* Pointer into name/filename */
+ *end; /* End of buffer */
+ int ch, /* Character from file */
+ fd, /* Temporary file descriptor */
+ blen; /* Length of boundary string */
+
+
+ DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary));
+
+ /*
+ * Read multipart form data until we run out...
+ */
+
+ name[0] = '\0';
+ filename[0] = '\0';
+ mimetype[0] = '\0';
+
+ snprintf(bstring, sizeof(bstring), "\r\n--%s", boundary);
+ blen = strlen(bstring);
+
+ while (fgets(line, sizeof(line), stdin))
+ {
+ if (!strcmp(line, "\r\n"))
+ {
+ /*
+ * End of headers, grab value...
+ */
+
+ if (filename[0])
+ {
+ /*
+ * Read an embedded file...
+ */
+
+ if (form_file)
+ {
+ /*
+ * Remove previous file...
+ */
+
+ cgi_unlink_file();
+ }
+
+ /*
+ * Allocate memory for the new file...
+ */
+
+ if ((form_file = calloc(1, sizeof(cgi_file_t))) == NULL)
+ return (0);
+
+ form_file->name = strdup(name);
+ form_file->filename = strdup(filename);
+ form_file->mimetype = strdup(mimetype);
+
+ fd = cupsTempFd(form_file->tempfile, sizeof(form_file->tempfile));
+
+ if (fd < 0)
+ return (0);
+
+ atexit(cgi_unlink_file);
+
+ /*
+ * Copy file data to the temp file...
+ */
+
+ ptr = line;
+
+ while ((ch = getchar()) != EOF)
+ {
+ *ptr++ = ch;
+
+ if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
+ {
+ ptr -= blen;
+ break;
+ }
+
+ if ((ptr - line - blen) >= 8192)
+ {
+ /*
+ * Write out the first 8k of the buffer...
+ */
+
+ write(fd, line, 8192);
+ memmove(line, line + 8192, ptr - line - 8192);
+ ptr -= 8192;
+ }
+ }
+
+ /*
+ * Write the rest of the data and close the temp file...
+ */
+
+ if (ptr > line)
+ write(fd, line, ptr - line);
+
+ close(fd);
+ }
+ else
+ {
+ /*
+ * Just get a form variable; the current code only handles
+ * form values up to 10k in size...
+ */
+
+ ptr = line;
+ end = line + sizeof(line) - 1;
+
+ while ((ch = getchar()) != EOF)
+ {
+ if (ptr < end)
+ *ptr++ = ch;
+
+ if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
+ {
+ ptr -= blen;
+ break;
+ }
+ }
+
+ *ptr = '\0';
+
+ /*
+ * Set the form variable...
+ */
+
+ if ((ptr = strrchr(name, '-')) != NULL && isdigit(ptr[1] & 255))
+ {
+ /*
+ * Set a specific index in the array...
+ */
+
+ *ptr++ = '\0';
+ if (line[0])
+ cgiSetArray(name, atoi(ptr) - 1, line);
+ }
+ else if (cgiGetVariable(name))
+ {
+ /*
+ * Add another element in the array...
+ */
+
+ cgiSetArray(name, cgiGetSize(name), line);
+ }
+ else
+ {
+ /*
+ * Just set the line...
+ */
+
+ cgiSetVariable(name, line);
+ }
+ }
+
+ /*
+ * Read the rest of the current line...
+ */
+
+ fgets(line, sizeof(line), stdin);
+
+ /*
+ * Clear the state vars...
+ */
+
+ name[0] = '\0';
+ filename[0] = '\0';
+ mimetype[0] = '\0';
+ }
+ else if (!strncasecmp(line, "Content-Disposition:", 20))
+ {
+ if ((ptr = strstr(line + 20, " name=\"")) != NULL)
+ {
+ strlcpy(name, ptr + 7, sizeof(name));
+
+ if ((ptr = strchr(name, '\"')) != NULL)
+ *ptr = '\0';
+ }
+
+ if ((ptr = strstr(line + 20, " filename=\"")) != NULL)
+ {
+ strlcpy(filename, ptr + 11, sizeof(filename));
+
+ if ((ptr = strchr(filename, '\"')) != NULL)
+ *ptr = '\0';
+ }
+ }
+ else if (!strncasecmp(line, "Content-Type:", 13))
+ {
+ for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
+
+ strlcpy(mimetype, ptr, sizeof(mimetype));
+
+ for (ptr = mimetype + strlen(mimetype) - 1;
+ ptr > mimetype && isspace(*ptr & 255);
+ *ptr-- = '\0');
+ }
+ }
+
+ /*
+ * Return 1 for "form data found"...
+ */
+
+ return (1);
+}
+
+
+/*
+ * '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 /* O - 1 if form data was processed */
+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] & 255))
+ {
+ *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_passwd()' - Catch authentication requests and notify the server.
+ *
+ * This function sends a Status header and exits, forcing authentication
+ * for this request.
+ */
+
+static const char * /* O - NULL (no return) */
+cgi_passwd(const char *prompt) /* I - Prompt (not used) */
+{
+ (void)prompt;
+
+ fprintf(stderr, "DEBUG: cgi_passwd(prompt=\"%s\") called!\n", prompt);
+
+ /*
+ * Send a 401 (unauthorized) status to the server, so it can notify
+ * the client that authentication is required.
+ */
+
+ puts("Status: 401\n");
+ exit(0);
+
+ /*
+ * This code is never executed, but is present to satisfy the compiler.
+ */
+
+ return (NULL);
+}
+
+
+/*
+ * '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(_cgi_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 */
+}
+
+
+/*
+ * 'cgi_unlink_file()' - Remove the uploaded form.
+ */
+
+static void
+cgi_unlink_file(void)
+{
+ if (form_file)
+ {
+ /*
+ * Remove the temporary file...
+ */
+
+ unlink(form_file->tempfile);
+
+ /*
+ * Free memory used...
+ */
+
+ free(form_file->name);
+ free(form_file->filename);
+ free(form_file->mimetype);
+ free(form_file);
+
+ form_file = NULL;
+ }
+}
+
+
+/*
+ * End of "$Id: var.c 4869 2005-12-06 02:43:40Z mike $".
+ */
diff --git a/conf/Makefile b/conf/Makefile
new file mode 100644
index 000000000..fe060d9c9
--- /dev/null
+++ b/conf/Makefile
@@ -0,0 +1,80 @@
+#
+# "$Id: Makefile 4664 2005-09-17 22:56:56Z mike $"
+#
+# Configuration file makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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:
+ $(INSTALL_DIR) $(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
+ -if test x$(PAMDIR) != x$(BUILDROOT); then \
+ $(INSTALL_DIR) $(PAMDIR); \
+ if test -r $(PAMDIR)/cups/$(PAMFILE) ; then \
+ $(INSTALL_DATA) $(PAMFILE) $(PAMDIR)/cups.N ; \
+ else \
+ $(INSTALL_DATA) $(PAMFILE) $(PAMDIR)/cups ; \
+ fi ; \
+ fi
+
+
+#
+# End of "$Id: Makefile 4664 2005-09-17 22:56:56Z mike $".
+#
diff --git a/conf/classes.conf b/conf/classes.conf
new file mode 100644
index 000000000..408796883
--- /dev/null
+++ b/conf/classes.conf
@@ -0,0 +1,89 @@
+#
+# "$Id: classes.conf 4494 2005-02-18 02:18:11Z mike $"
+#
+# Sample class configuration file for the Common UNIX Printing System
+# (CUPS) scheduler.
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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 4494 2005-02-18 02:18:11Z mike $".
+#
diff --git a/conf/client.conf b/conf/client.conf
new file mode 100644
index 000000000..dfe332165
--- /dev/null
+++ b/conf/client.conf
@@ -0,0 +1,67 @@
+#
+# "$Id: client.conf 4494 2005-02-18 02:18:11Z mike $"
+#
+# Sample client configuration file for the Common UNIX Printing System
+# (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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. ONLY ONE SERVER NAME MAY BE SPECIFIED AT A TIME. To use
+# more than one server you must use a local scheduler with browsing
+# and possibly polling.
+#
+
+#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 4494 2005-02-18 02:18:11Z mike $".
+#
diff --git a/conf/cupsd.conf.in b/conf/cupsd.conf.in
new file mode 100644
index 000000000..e3b73ea7a
--- /dev/null
+++ b/conf/cupsd.conf.in
@@ -0,0 +1,76 @@
+#
+# "$Id: cupsd.conf.in 4817 2005-11-04 16:21:01Z mike $"
+#
+# Sample configuration file for the Common UNIX Printing System (CUPS)
+# scheduler. See "man cupsd.conf" for a complete description of this
+# file.
+#
+
+# Log general information in error_log - change "info" to "debug" for
+# troubleshooting...
+LogLevel info
+
+# Administrator user group...
+SystemGroup @CUPS_GROUP@
+
+# Only listen for connections from the local machine.
+Listen localhost:@DEFAULT_IPP_PORT@
+@CUPS_LISTEN_DOMAINSOCKET@
+
+# Show shared printers on the local network.
+Browsing On
+BrowseOrder allow,deny
+BrowseAllow @LOCAL
+
+# Default authentication type, when authentication is required...
+DefaultAuthType Basic
+
+# Restrict access to the server...
+
+ Order allow,deny
+ Allow localhost
+
+
+# Restrict access to the admin pages...
+
+ Order allow,deny
+ Allow localhost
+
+
+# Restrict access to configuration files...
+
+ AuthType Basic
+ Require user @SYSTEM
+ Order allow,deny
+ Allow localhost
+
+
+# Set the default printer/job policies...
+
+ # Job-related operations must be done by the owner or an adminstrator...
+
+ Require user @OWNER @SYSTEM
+ Order deny,allow
+
+
+ # All administration operations require an adminstrator to authenticate...
+
+ AuthType Basic
+ Require user @SYSTEM
+ Order deny,allow
+
+
+ # Only the owner or an administrator can cancel or authenticate a job...
+
+ Require user @OWNER @SYSTEM
+ Order deny,allow
+
+
+
+ Order deny,allow
+
+
+
+#
+# End of "$Id: cupsd.conf.in 4817 2005-11-04 16:21:01Z mike $".
+#
diff --git a/conf/mime.convs b/conf/mime.convs
new file mode 100644
index 000000000..b6c7004ba
--- /dev/null
+++ b/conf/mime.convs
@@ -0,0 +1,119 @@
+#
+# "$Id: mime.convs 4559 2005-08-04 18:40:13Z mike $"
+#
+# MIME converts file for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+########################################################################
+#
+# Format of Lines:
+#
+# source/type destination/type cost filter
+#
+# General Notes:
+#
+# The "cost" field is used to find the least costly filters to run
+# when converting a job file to a printable format.
+#
+# All filters *must* accept the standard command-line arguments
+# (job-id, user, title, copies, options, [filename or stdin]) to
+# work with CUPS.
+#
+
+########################################################################
+#
+# PostScript filters
+#
+
+application/pdf application/postscript 33 pdftops
+application/postscript application/vnd.cups-postscript 66 pstops
+application/vnd.hp-HPGL application/postscript 66 hpgltops
+application/x-cshell application/postscript 33 texttops
+application/x-csource application/postscript 33 texttops
+application/x-perl application/postscript 33 texttops
+application/x-shell application/postscript 33 texttops
+text/plain application/postscript 33 texttops
+text/html application/postscript 33 texttops
+image/gif application/vnd.cups-postscript 66 imagetops
+image/png application/vnd.cups-postscript 66 imagetops
+image/jpeg application/vnd.cups-postscript 66 imagetops
+image/tiff application/vnd.cups-postscript 66 imagetops
+image/x-bitmap application/vnd.cups-postscript 66 imagetops
+image/x-photocd application/vnd.cups-postscript 66 imagetops
+image/x-portable-anymap application/vnd.cups-postscript 66 imagetops
+image/x-portable-bitmap application/vnd.cups-postscript 66 imagetops
+image/x-portable-graymap application/vnd.cups-postscript 66 imagetops
+image/x-portable-pixmap application/vnd.cups-postscript 66 imagetops
+image/x-sgi-rgb application/vnd.cups-postscript 66 imagetops
+image/x-xbitmap application/vnd.cups-postscript 66 imagetops
+image/x-xpixmap application/vnd.cups-postscript 66 imagetops
+#image/x-xwindowdump application/vnd.cups-postscript 66 imagetops
+image/x-sun-raster application/vnd.cups-postscript 66 imagetops
+
+
+########################################################################
+#
+# Form filter...
+#
+# This filter does not currently exist, but the file format is defined
+# in the IDD and registered with the IANA for future use...
+#
+
+#application/vnd.cups-form application/vnd.cups-postscript 33 formtops
+
+########################################################################
+#
+# Raster filters...
+#
+
+image/gif application/vnd.cups-raster 100 imagetoraster
+image/png application/vnd.cups-raster 100 imagetoraster
+image/jpeg application/vnd.cups-raster 100 imagetoraster
+image/tiff application/vnd.cups-raster 100 imagetoraster
+image/x-bitmap application/vnd.cups-raster 100 imagetoraster
+image/x-photocd application/vnd.cups-raster 100 imagetoraster
+image/x-portable-anymap application/vnd.cups-raster 100 imagetoraster
+image/x-portable-bitmap application/vnd.cups-raster 100 imagetoraster
+image/x-portable-graymap application/vnd.cups-raster 100 imagetoraster
+image/x-portable-pixmap application/vnd.cups-raster 100 imagetoraster
+image/x-sgi-rgb application/vnd.cups-raster 100 imagetoraster
+image/x-xbitmap application/vnd.cups-raster 100 imagetoraster
+image/x-xpixmap application/vnd.cups-raster 100 imagetoraster
+#image/x-xwindowdump application/vnd.cups-raster 100 imagetoraster
+image/x-sun-raster application/vnd.cups-raster 100 imagetoraster
+
+# pstoraster is now part of ESP Ghostscript...
+#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/octet-stream application/vnd.cups-raw 0 -
+
+#
+# End of "$Id: mime.convs 4559 2005-08-04 18:40:13Z mike $".
+#
diff --git a/conf/mime.types b/conf/mime.types
new file mode 100644
index 000000000..8d738aaed
--- /dev/null
+++ b/conf/mime.types
@@ -0,0 +1,169 @@
+#
+# "$Id: mime.types 4590 2005-08-24 19:25:49Z mike $"
+#
+# MIME types file for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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
+# istring(offset,"string") True if bytes are identical to
+# case-insensitive 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>%!) \
+ contains(0,128,<1B>%-12345X) + \
+ (contains(0,1024,"LANGUAGE=POSTSCRIPT") \
+ contains(0,1024,"LANGUAGE = Postscript") \
+ contains(0,1024,"LANGUAGE = PostScript") \
+ contains(0,1024,"LANGUAGE = POSTSCRIPT"))
+application/vnd.hp-HPGL hpgl string(0,<1B>&)\
+ string(0,<1B>E<1B>%0B) \
+ string(0,<1B>%-1B) string(0,<201B>)\
+ string(0,BP;) string(0,IN;) string(0,DF;) \
+ string(0,BPINPS;) \
+ (contains(0,128,<1B>%-12345X) + \
+ (contains(0,1024,"LANGUAGE=HPGL") \
+ contains(0,1024,"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 string(4,<00000007>)
+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)
+image/x-icon ico
+
+########################################################################
+#
+# Text files...
+#
+
+application/x-cshell csh printable(0,1024) + string(0,#!) +\
+ (contains(2,80,/csh) contains(2,80,/tcsh))
+application/x-perl pl printable(0,1024) + string(0,#!) +\
+ contains(2,80,/perl)
+application/x-shell sh printable(0,1024) + string(0,#!) +\
+ (contains(2,80,/bash) contains(2,80,/ksh)\
+ contains(2,80,/sh) contains(2,80,/zsh))
+application/x-csource c cxx cpp cc C h hpp \
+ printable(0,1024) + \
+ (string(0,/*) string(0,//)
+ string(0,#include) contains(0,1024,<0a>#include) \
+ string(0,#define) contains(0,1024,<0a>#define))
+text/html html htm printable(0,1024) +\
+ (istring(0,"") istring(0,"")
+application/vnd.cups-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>@) \
+ (contains(0,128,<1B>%-12345X) + \
+ (contains(0,1024,"LANGUAGE=PCL") \
+ contains(0,1024,"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 4590 2005-08-24 19:25:49Z mike $".
+#
diff --git a/conf/pam.darwin b/conf/pam.darwin
new file mode 100644
index 000000000..ff724da4d
--- /dev/null
+++ b/conf/pam.darwin
@@ -0,0 +1,7 @@
+# cups: auth account password session
+auth sufficient pam_securityserver.so
+auth sufficient pam_unix.so
+auth required pam_deny.so
+account required pam_permit.so
+password required pam_deny.so
+session required pam_permit.so
diff --git a/conf/pam.irix b/conf/pam.irix
new file mode 100644
index 000000000..476383acb
--- /dev/null
+++ b/conf/pam.irix
@@ -0,0 +1,3 @@
+#%PAM-1.0
+auth required pam_unix.so shadow nodelay nullok
+account required pam_unix.so
diff --git a/conf/pam.std.in b/conf/pam.std.in
new file mode 100644
index 000000000..3ddcdd0d3
--- /dev/null
+++ b/conf/pam.std.in
@@ -0,0 +1,2 @@
+auth required @PAMMOD@ nullok shadow
+account required @PAMMOD@
diff --git a/conf/printcap b/conf/printcap
new file mode 100644
index 000000000..230c3017d
--- /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 000000000..3848459c9
--- /dev/null
+++ b/conf/printers.conf
@@ -0,0 +1,96 @@
+#
+# "$Id: printers.conf 4494 2005-02-18 02:18:11Z mike $"
+#
+# Sample printer configuration file for the Common UNIX Printing System
+# (CUPS) scheduler.
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# 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 4494 2005-02-18 02:18:11Z mike $".
+#
diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4
new file mode 100644
index 000000000..045991676
--- /dev/null
+++ b/config-scripts/cups-common.m4
@@ -0,0 +1,197 @@
+dnl
+dnl "$Id: cups-common.m4 4833 2005-11-12 21:46:52Z mike $"
+dnl
+dnl Common configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl We need at least autoconf 2.50...
+AC_PREREQ(2.50)
+
+dnl Set the name of the config header file...
+AC_CONFIG_HEADER(config.h)
+
+dnl Versio number information...
+CUPS_VERSION="1.2svn"
+AC_SUBST(CUPS_VERSION)
+AC_DEFINE_UNQUOTED(CUPS_SVERSION, "CUPS v$CUPS_VERSION")
+AC_DEFINE_UNQUOTED(CUPS_MINIMAL, "CUPS/$CUPS_VERSION")
+
+dnl Default compiler flags...
+CFLAGS="${CFLAGS:=}"
+CPPFLAGS="${CPPFLAGS:=}"
+CXXFLAGS="${CXXFLAGS:=}"
+LDFLAGS="${LDFLAGS:=}"
+
+dnl Checks for programs...
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+AC_PROG_INSTALL
+if test "$INSTALL" = "$ac_install_sh"; then
+ # Use full path to install-sh script...
+ INSTALL="`pwd`/install-sh -c"
+fi
+AC_PROG_RANLIB
+AC_PATH_PROG(AR,ar)
+AC_PATH_PROG(HTMLDOC,htmldoc)
+AC_PATH_PROG(LN,ln)
+AC_PATH_PROG(MV,mv)
+AC_PATH_PROG(RM,rm)
+AC_PATH_PROG(SED,sed)
+AC_PATH_PROG(STRIP,strip)
+
+if test "x$AR" = x; then
+ AC_MSG_ERROR([Unable to find required library archive command.])
+fi
+if test "x$CC" = x; then
+ AC_MSG_ERROR([Unable to find required C compiler command.])
+fi
+if test "x$CXX" = x; then
+ AC_MSG_ERROR([Unable to find required C++ compiler command.])
+fi
+
+dnl Architecture checks...
+AC_C_BIGENDIAN
+
+dnl Check for libraries...
+AC_SEARCH_LIBS(crypt, crypt)
+AC_SEARCH_LIBS(getspent, sec gen)
+
+LIBMALLOC=""
+AC_ARG_ENABLE(mallinfo, [ --enable-mallinfo turn on malloc debug information, default=no])
+
+if test x$enable_mallinfo = xyes; then
+ 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
+fi
+
+AC_SUBST(LIBMALLOC)
+
+dnl Check for libpaper support...
+AC_ARG_ENABLE(libpaper, [ --enable-libpaper turn on libpaper support, default=no])
+
+if test x$enable_libpaper = xyes; then
+ AC_CHECK_LIB(paper,systempapername,
+ AC_DEFINE(HAVE_LIBPAPER)
+ LIBPAPER="-lpaper",
+ LIBPAPER="")
+else
+ LIBPAPER=""
+fi
+AC_SUBST(LIBPAPER)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADER(crypt.h,AC_DEFINE(HAVE_CRYPT_H))
+AC_CHECK_HEADER(langinfo.h,AC_DEFINE(HAVE_LANGINFO_H))
+AC_CHECK_HEADER(malloc.h,AC_DEFINE(HAVE_MALLOC_H))
+AC_CHECK_HEADER(shadow.h,AC_DEFINE(HAVE_SHADOW_H))
+AC_CHECK_HEADER(string.h,AC_DEFINE(HAVE_STRING_H))
+AC_CHECK_HEADER(strings.h,AC_DEFINE(HAVE_STRINGS_H))
+AC_CHECK_HEADER(bstring.h,AC_DEFINE(HAVE_BSTRING_H))
+AC_CHECK_HEADER(usersec.h,AC_DEFINE(HAVE_USERSEC_H))
+AC_CHECK_HEADER(sys/ioctl.h,AC_DEFINE(HAVE_SYS_IOCTL_H))
+
+dnl Checks for string functions.
+AC_CHECK_FUNCS(strdup strcasecmp strncasecmp strlcat strlcpy)
+if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then
+ echo Forcing snprintf emulation for HP-UX.
+else
+ AC_CHECK_FUNCS(snprintf vsnprintf)
+fi
+
+dnl Checks for mkstemp and mkstemps functions.
+AC_CHECK_FUNCS(mkstemp mkstemps)
+
+dnl Check for geteuid function.
+AC_CHECK_FUNCS(geteuid)
+
+dnl Check for vsyslog function.
+AC_CHECK_FUNCS(vsyslog)
+
+dnl Checks for signal functions.
+case "$uname" in
+ Linux | GNU)
+ # Do not use sigset on Linux or GNU HURD
+ ;;
+ *)
+ # Use sigset on other platforms, if available
+ AC_CHECK_FUNCS(sigset)
+ ;;
+esac
+
+AC_CHECK_FUNCS(sigaction)
+
+dnl Checks for wait functions.
+AC_CHECK_FUNCS(waitpid)
+AC_CHECK_FUNCS(wait3)
+
+dnl See if the tm structure has the tm_gmtoff member...
+AC_MSG_CHECKING(for tm_gmtoff member in tm structure)
+AC_TRY_COMPILE([#include ],[struct tm t;
+ int o = t.tm_gmtoff;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_TM_GMTOFF),
+ AC_MSG_RESULT(no))
+
+dnl Flags for "ar" command...
+case $uname in
+ Darwin* | *BSD*)
+ ARFLAGS="-rcv"
+ ;;
+ *)
+ ARFLAGS="crvs"
+ ;;
+esac
+
+AC_SUBST(ARFLAGS)
+
+dnl Extra platform-specific libraries...
+case $uname in
+ Darwin*)
+ BACKLIBS="-framework IOKit"
+ LIBS="-framework CoreFoundation $LIBS"
+ ;;
+ *)
+ BACKLIBS=""
+ ;;
+esac
+
+AC_SUBST(BACKLIBS)
+
+dnl New default port definition for IPP...
+AC_ARG_WITH(ipp-port, [ --with-ipp-port set default port number for IPP ],
+ DEFAULT_IPP_PORT="$withval",
+ DEFAULT_IPP_PORT="631")
+
+AC_SUBST(DEFAULT_IPP_PORT)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IPP_PORT,$DEFAULT_IPP_PORT)
+
+dnl
+dnl End of "$Id: cups-common.m4 4833 2005-11-12 21:46:52Z mike $".
+dnl
diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4
new file mode 100644
index 000000000..f597e2773
--- /dev/null
+++ b/config-scripts/cups-compiler.m4
@@ -0,0 +1,200 @@
+dnl
+dnl "$Id: cups-compiler.m4 4915 2006-01-11 15:57:53Z mike $"
+dnl
+dnl Compiler stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2006 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl Clear the debugging and non-shared library options unless the user asks
+dnl for them...
+OPTIM=""
+AC_SUBST(OPTIM)
+
+AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging, default=no],
+ [if test x$enable_debug = xyes; then
+ OPTIM="-g"
+ fi])
+
+AC_ARG_WITH(optim, [ --with-optim="flags" set optimization flags ])
+
+dnl Update compiler options...
+CXXLIBS=""
+AC_SUBST(CXXLIBS)
+
+if test -n "$GCC"; then
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ # Default to optimize-for-size and debug
+ OPTIM="-Os -g"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test $PICFLAG = 1 -a $uname != AIX; then
+ OPTIM="-fPIC $OPTIM"
+ fi
+
+ case $uname in
+ Darwin*)
+ if test "x$with_optim" = x; then
+ if test "x`uname -m`" = xi386; then
+ # Build universal binaries for OSX on Intel...
+ OPTIM="-arch i386 -arch ppc $OPTIM"
+ DSOFLAGS="-arch i386 -arch ppc $DSOFLAGS"
+ fi
+ fi
+ ;;
+
+ Linux*)
+ AC_MSG_CHECKING(if GCC supports -fpie)
+
+ OLDCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fpie"
+ AC_TRY_COMPILE(,,
+ OPTIM="$OPTIM -fpie"
+ LDFLAGS="$LDFLAGS -pie"
+ AC_MSG_RESULT(yes),
+ CFLAGS="$OLDCFLAGS"
+ AC_MSG_RESULT(no))
+ ;;
+ esac
+
+ if test "x$with_optim" = x; then
+ # Add useful warning options for tracking down problems...
+ OPTIM="-Wall -Wno-format-y2k $OPTIM"
+ # Additional warning options for alpha testing...
+ OPTIM="-Wshadow -Wunused $OPTIM"
+ fi
+else
+ case $uname in
+ AIX*)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O2 -qmaxmem=6000"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+ ;;
+ HP-UX*)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="+O2"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ CFLAGS="-Ae $CFLAGS"
+
+ if test "x$with_optim" = x; then
+ OPTIM="+DAportable $OPTIM"
+ fi
+
+ if test $PICFLAG = 1; then
+ OPTIM="+z $OPTIM"
+ fi
+ ;;
+ IRIX)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O2"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test $uversion -ge 62 -a "x$with_optim" = x; then
+ OPTIM="$OPTIM -n32 -mips3"
+ fi
+
+ if test "x$with_optim" = x; then
+ # Show most warnings, but suppress the
+ # ones about arguments not being used,
+ # string constants assigned to const
+ # char *'s, etc. We only set the warning
+ # options on IRIX 6.2 and higher because
+ # of limitations in the older SGI compiler
+ # tools.
+ if test $uversion -ge 62; then
+ OPTIM="-fullwarn -woff 1183,1209,1349,3201 $OPTIM"
+ fi
+ fi
+ ;;
+ SunOS*)
+ # Solaris
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-xO4"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test "x$with_optim" = x; then
+ # Specify "generic" SPARC output and suppress
+ # all of Sun's questionable warning messages...
+ OPTIM="-w $OPTIM -xarch=generic"
+ fi
+
+ if test $PICFLAG = 1; then
+ OPTIM="-KPIC $OPTIM"
+ fi
+ ;;
+ UNIX_SVR*)
+ # UnixWare
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ 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-bugs@cups.org with uname and compiler options needed"
+ echo "for your platform, or set the CFLAGS and CXXFLAGS"
+ echo "environment variable before running configure."
+ ;;
+ esac
+fi
+
+if test $uname = HP-UX; then
+ # HP-UX 10.20 (at least) needs this definition to get the
+ # h_errno global...
+ OPTIM="$OPTIM -D_XOPEN_SOURCE_EXTENDED"
+
+ # HP-UX 11.00 (at least) needs this definition to get the
+ # u_short type used by the IP headers...
+ OPTIM="$OPTIM -D_INCLUDE_HPUX_SOURCE"
+fi
+
+dnl
+dnl End of "$Id: cups-compiler.m4 4915 2006-01-11 15:57:53Z mike $".
+dnl
diff --git a/config-scripts/cups-directories.m4 b/config-scripts/cups-directories.m4
new file mode 100644
index 000000000..9cbcc26aa
--- /dev/null
+++ b/config-scripts/cups-directories.m4
@@ -0,0 +1,279 @@
+dnl
+dnl "$Id: cups-directories.m4 4873 2005-12-07 01:46:54Z mike $"
+dnl
+dnl Directory stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_PREFIX_DEFAULT(/)
+
+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 "bindir" variable...
+if test "$bindir" = "\${exec_prefix}/bin"; then
+ bindir="$exec_prefix/bin"
+fi
+
+dnl Fix "sbindir" variable...
+if test "$sbindir" = "\${exec_prefix}/sbin"; then
+ sbindir="$exec_prefix/sbin"
+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
+ if test "$uname" = Darwin; then
+ localstatedir="/private/var"
+ else
+ localstatedir="/var"
+ fi
+ 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
+ if test "$uname" = Darwin; then
+ sysconfdir="/private/etc"
+ else
+ sysconfdir="/etc"
+ fi
+ else
+ sysconfdir="$prefix/etc"
+ fi
+fi
+
+dnl Fix "libdir" variable for IRIX 6.x...
+if test "$libdir" = "\${exec_prefix}/lib"; then
+ if test "$uname" = "IRIX" -a $uversion -ge 62; then
+ libdir="$exec_prefix/lib32"
+ else
+ libdir="$exec_prefix/lib"
+ fi
+fi
+
+dnl Setup init.d locations...
+AC_ARG_WITH(rcdir, [ --with-rcdir set path for rc scripts],rcdir="$withval",rcdir="")
+
+if test x$rcdir = x; then
+ case "$uname" in
+ FreeBSD* | OpenBSD*)
+ # FreeBSD and OpenBSD
+ INITDIR=""
+ INITDDIR=""
+ ;;
+
+ NetBSD*)
+ # NetBSD
+ INITDIR=""
+ INITDDIR="/etc/rc.d"
+ ;;
+
+ Darwin*)
+ # Darwin and MacOS X...
+ INITDIR=""
+ INITDDIR="/System/Library/StartupItems/PrintingServices"
+ ;;
+
+ Linux | GNU)
+ # Linux/HURD 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/init.d; then
+ # Others
+ INITDIR="/etc"
+ INITDDIR="../init.d"
+ else
+ # RedHat
+ INITDIR="/etc/rc.d"
+ INITDDIR="../init.d"
+ fi
+ fi
+ ;;
+
+ OSF1* | HP-UX*)
+ INITDIR="/sbin"
+ INITDDIR="../init.d"
+ ;;
+
+ AIX*)
+ INITDIR="/etc/rc.d"
+ INITDDIR=".."
+ ;;
+
+ *)
+ INITDIR="/etc"
+ INITDDIR="../init.d"
+ ;;
+
+ esac
+else
+ INITDIR=""
+ INITDDIR="$rcdir"
+fi
+
+AC_SUBST(INITDIR)
+AC_SUBST(INITDDIR)
+
+dnl Setup default locations...
+# Cache data...
+AC_ARG_WITH(cachedir, [ --with-cachedir set path for cache files],cachedir="$withval",cachedir="")
+
+if test x$cachedir = x; then
+ CUPS_CACHEDIR="$localstatedir/cache/cups"
+else
+ CUPS_CACHEDIR="$cachedir"
+fi
+AC_DEFINE_UNQUOTED(CUPS_CACHEDIR, "$CUPS_CACHEDIR")
+AC_SUBST(CUPS_CACHEDIR)
+
+# Data files
+CUPS_DATADIR="$datadir/cups"
+AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$datadir/cups")
+AC_SUBST(CUPS_DATADIR)
+
+# Documentation files
+AC_ARG_WITH(docdir, [ --with-docdir set path for documentation],docdir="$withval",docdir="")
+
+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)
+
+# Fonts
+AC_ARG_WITH(fontpath, [ --with-fontpath set font path for pstoraster],fontpath="$withval",fontpath="")
+
+if test "x$fontpath" = "x"; then
+ CUPS_FONTPATH="$datadir/cups/fonts"
+else
+ CUPS_FONTPATH="$fontpath"
+fi
+
+AC_SUBST(CUPS_FONTPATH)
+AC_DEFINE_UNQUOTED(CUPS_FONTPATH, "$CUPS_FONTPATH")
+
+# Locale data
+case "$uname" in
+ Linux | GNU | *BSD* | Darwin*)
+ CUPS_LOCALEDIR="$datadir/locale"
+ ;;
+
+ OSF1* | AIX*)
+ CUPS_LOCALEDIR="$exec_prefix/lib/nls/msg"
+ ;;
+
+ *)
+ # This is the standard System V location...
+ CUPS_LOCALEDIR="$exec_prefix/lib/locale"
+ ;;
+esac
+
+AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$CUPS_LOCALEDIR")
+AC_SUBST(CUPS_LOCALEDIR)
+
+# Log files...
+AC_ARG_WITH(logdir, [ --with-logdir set path for log files],logdir="$withval",logdir="")
+
+if test x$logdir = x; then
+ CUPS_LOGDIR="$localstatedir/log/cups"
+ AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$localstatedir/log/cups")
+else
+ CUPS_LOGDIR="$logdir"
+fi
+AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$CUPS_LOGDIR")
+AC_SUBST(CUPS_LOGDIR)
+
+# Longer-term spool data
+CUPS_REQUESTS="$localstatedir/spool/cups"
+AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$localstatedir/spool/cups")
+AC_SUBST(CUPS_REQUESTS)
+
+# Server executables...
+case "$uname" in
+ *BSD* | Darwin*)
+ # *BSD and Darwin (MacOS X)
+ INSTALL_SYSV=""
+ CUPS_SERVERBIN="$exec_prefix/libexec/cups"
+ ;;
+ *)
+ # All others
+ INSTALL_SYSV="install-sysv"
+ CUPS_SERVERBIN="$libdir/cups"
+ ;;
+esac
+
+AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$CUPS_SERVERBIN")
+AC_SUBST(CUPS_SERVERBIN)
+AC_SUBST(INSTALL_SYSV)
+
+# Configuration files
+CUPS_SERVERROOT="$sysconfdir/cups"
+AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$sysconfdir/cups")
+AC_SUBST(CUPS_SERVERROOT)
+
+# Transient run-time state
+CUPS_STATEDIR="$localstatedir/run/cups"
+AC_DEFINE_UNQUOTED(CUPS_STATEDIR, "$localstatedir/run/cups")
+AC_SUBST(CUPS_STATEDIR)
+
+dnl
+dnl End of "$Id: cups-directories.m4 4873 2005-12-07 01:46:54Z mike $".
+dnl
diff --git a/config-scripts/cups-image.m4 b/config-scripts/cups-image.m4
new file mode 100644
index 000000000..940b0bbdd
--- /dev/null
+++ b/config-scripts/cups-image.m4
@@ -0,0 +1,98 @@
+dnl
+dnl "$Id: cups-image.m4 4644 2005-09-15 18:43:06Z mike $"
+dnl
+dnl Image library stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+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...
+AC_ARG_ENABLE(jpeg, [ --enable-jpeg turn on JPEG support, default=yes])
+AC_ARG_ENABLE(png, [ --enable-png turn on PNG support, default=yes])
+AC_ARG_ENABLE(tiff, [ --enable-tiff turn on TIFF support, default=yes])
+
+LIBJPEG=""
+LIBPNG=""
+LIBTIFF=""
+LIBZ=""
+
+AC_SUBST(LIBJPEG)
+AC_SUBST(LIBPNG)
+AC_SUBST(LIBTIFF)
+AC_SUBST(LIBZ)
+
+if test x$enable_jpeg != xno; then
+ AC_CHECK_HEADER(jpeglib.h,
+ AC_CHECK_LIB(jpeg, jpeg_destroy_decompress,
+ AC_DEFINE(HAVE_LIBJPEG)
+ LIBJPEG="-ljpeg"
+ LIBS="$LIBS -ljpeg"))
+else
+ AC_MSG_NOTICE([JPEG support disabled with --disable-jpeg.])
+fi
+
+AC_CHECK_HEADER(zlib.h,
+ 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)
+
+if test x$enable_png != xno; then
+ AC_CHECK_HEADER(png.h,
+ AC_CHECK_LIB(png, png_set_tRNS_to_alpha,
+ AC_DEFINE(HAVE_LIBPNG)
+ LIBPNG="-lpng -lm"))
+else
+ AC_MSG_NOTICE([PNG support disabled with --disable-png.])
+fi
+
+if test x$enable_tiff != xno; then
+ AC_CHECK_HEADER(tiff.h,
+ AC_CHECK_LIB(tiff, TIFFReadScanline,
+ AC_DEFINE(HAVE_LIBTIFF)
+ LIBTIFF="-ltiff"))
+else
+ AC_MSG_NOTICE([TIFF support disabled with --disable-tiff.])
+fi
+
+dnl Restore original LIBS settings...
+LIBS="$SAVELIBS"
+
+EXPORT_LIBJPEG="$LIBJPEG"
+EXPORT_LIBPNG="$LIBPNG"
+EXPORT_LIBTIFF="$LIBTIFF"
+EXPORT_LIBZ="$LIBZ"
+
+AC_SUBST(EXPORT_LIBJPEG)
+AC_SUBST(EXPORT_LIBPNG)
+AC_SUBST(EXPORT_LIBTIFF)
+AC_SUBST(EXPORT_LIBZ)
+
+AC_CHECK_HEADER(stdlib.h,AC_DEFINE(HAVE_STDLIB_H))
+
+dnl
+dnl End of "$Id: cups-image.m4 4644 2005-09-15 18:43:06Z mike $".
+dnl
diff --git a/config-scripts/cups-largefile.m4 b/config-scripts/cups-largefile.m4
new file mode 100644
index 000000000..25400ce2d
--- /dev/null
+++ b/config-scripts/cups-largefile.m4
@@ -0,0 +1,61 @@
+dnl
+dnl "$Id: cups-largefile.m4 4732 2005-09-30 23:23:25Z mike $"
+dnl
+dnl Large file support stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl Check for largefile support...
+AC_SYS_LARGEFILE
+
+dnl Define largefile options as needed...
+LARGEFILE=""
+if test x$enable_largefile != xno; then
+ LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+
+ if test $ac_cv_sys_large_files = 1; then
+ LARGEFILE="$LARGEFILE -D_LARGE_FILES"
+ fi
+
+ if test $ac_cv_sys_file_offset_bits = 64; then
+ LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64"
+ fi
+fi
+AC_SUBST(LARGEFILE)
+
+dnl Check for "long long" support...
+AC_CACHE_CHECK(for long long int, ac_cv_c_long_long,
+ [if test "$GCC" = yes; then
+ ac_cv_c_long_long=yes
+ else
+ AC_TRY_COMPILE(,[long long int i;],
+ ac_cv_c_long_long=yes,
+ ac_cv_c_long_long=no)
+ fi])
+
+if test $ac_cv_c_long_long = yes; then
+ AC_DEFINE(HAVE_LONG_LONG)
+fi
+
+AC_CHECK_FUNC(strtoll, AC_DEFINE(HAVE_STRTOLL))
+
+dnl
+dnl End of "$Id: cups-largefile.m4 4732 2005-09-30 23:23:25Z mike $".
+dnl
diff --git a/config-scripts/cups-libtool.m4 b/config-scripts/cups-libtool.m4
new file mode 100644
index 000000000..0d8673c79
--- /dev/null
+++ b/config-scripts/cups-libtool.m4
@@ -0,0 +1,49 @@
+dnl
+dnl "$Id: cups-libtool.m4 4494 2005-02-18 02:18:11Z mike $"
+dnl
+dnl Libtool stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_ARG_ENABLE(libtool_unsupported, [ --enable-libtool-unsupported=LIBTOOL_PATH
+ turn on building with libtool (UNSUPPORTED!), default=no],
+ [if 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])
+
+AC_SUBST(LIBTOOL)
+
+if test x$LIBTOOL != x; then
+ LIBCUPS="libcups.la"
+ LIBCUPSIMAGE="libcupsimage.la"
+ LINKCUPS="../cups/\$(LIBCUPS)"
+ LINKCUPSIMAGE="../filter/\$(LIBCUPSIMAGE)"
+ DSO="\$(CC)"
+fi
+
+dnl
+dnl End of "$Id: cups-libtool.m4 4494 2005-02-18 02:18:11Z mike $".
+dnl
diff --git a/config-scripts/cups-manpages.m4 b/config-scripts/cups-manpages.m4
new file mode 100644
index 000000000..6a887d13d
--- /dev/null
+++ b/config-scripts/cups-manpages.m4
@@ -0,0 +1,101 @@
+dnl
+dnl "$Id: cups-manpages.m4 4833 2005-11-12 21:46:52Z mike $"
+dnl
+dnl Manpage stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl Fix "mandir" variable...
+if test "$mandir" = "\${prefix}/man" -a "$prefix" = "/"; then
+ case "$uname" in
+ Darwin* | Linux | GNU | *BSD* | AIX*)
+ # Darwin, MacOS X, Linux, GNU HURD, *BSD, and AIX
+ mandir="/usr/share/man"
+ AMANDIR="/usr/share/man"
+ PMANDIR="/usr/share/man"
+ ;;
+ IRIX)
+ # SGI IRIX
+ mandir="/usr/share/catman/u_man"
+ AMANDIR="/usr/share/catman/a_man"
+ PMANDIR="/usr/share/catman/p_man"
+ ;;
+ *)
+ # All others
+ mandir="/usr/man"
+ AMANDIR="/usr/man"
+ PMANDIR="/usr/man"
+ ;;
+ esac
+else
+ AMANDIR="$mandir"
+ PMANDIR="$mandir"
+fi
+
+AC_SUBST(AMANDIR)
+AC_SUBST(PMANDIR)
+
+dnl Setup manpage extensions...
+case "$uname" in
+ *BSD* | Darwin*)
+ # *BSD
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+ IRIX*)
+ # SGI IRIX
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN8EXT=1m
+ MAN8DIR=1
+ ;;
+ SunOS* | HP-UX*)
+ # Solaris and HP-UX
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN8EXT=1m
+ MAN8DIR=1m
+ ;;
+ Linux* | GNU*)
+ # Linux and GNU Hurd
+ MAN1EXT=1.gz
+ MAN5EXT=5.gz
+ MAN8EXT=8.gz
+ MAN8DIR=8
+ ;;
+ *)
+ # All others
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+esac
+
+AC_SUBST(MAN1EXT)
+AC_SUBST(MAN5EXT)
+AC_SUBST(MAN8EXT)
+AC_SUBST(MAN8DIR)
+
+dnl
+dnl End of "$Id: cups-manpages.m4 4833 2005-11-12 21:46:52Z mike $".
+dnl
diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4
new file mode 100644
index 000000000..e5abc8ba9
--- /dev/null
+++ b/config-scripts/cups-network.m4
@@ -0,0 +1,89 @@
+dnl
+dnl "$Id: cups-network.m4 4873 2005-12-07 01:46:54Z mike $"
+dnl
+dnl Networking stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_SEARCH_LIBS(socket, socket)
+AC_SEARCH_LIBS(gethostbyaddr, nsl)
+AC_SEARCH_LIBS(getaddrinfo, nsl, AC_DEFINE(HAVE_GETADDRINFO))
+AC_SEARCH_LIBS(getifaddrs, nsl, AC_DEFINE(HAVE_GETIFADDRS))
+AC_SEARCH_LIBS(getnameinfo, nsl, AC_DEFINE(HAVE_GETNAMEINFO))
+AC_SEARCH_LIBS(hstrerror, nsl socket resolv, AC_DEFINE(HAVE_HSTRERROR))
+AC_SEARCH_LIBS(rresvport_af, nsl, AC_DEFINE(HAVE_RRESVPORT_AF))
+
+AC_CHECK_MEMBER(struct sockaddr.sa_len,,, [#include ])
+AC_CHECK_HEADER(sys/sockio.h, AC_DEFINE(HAVE_SYS_SOCKIO_H))
+
+if test "$uname" = "SunOS"; then
+ case "$uversion" in
+ 55* | 56*)
+ maxfiles=1024
+ ;;
+ *)
+ maxfiles=4096
+ ;;
+ esac
+else
+ maxfiles=4096
+fi
+
+AC_ARG_WITH(maxfiles, [ --with-maxfiles=N set maximum number of file descriptors for scheduler ],
+ maxfiles=$withval)
+
+AC_DEFINE_UNQUOTED(CUPS_MAX_FDS, $maxfiles)
+
+CUPS_DEFAULT_DOMAINSOCKET=""
+
+dnl Domain socket support...
+AC_ARG_WITH(domainsocket, [ --with-domainsocket set unix domain socket name],
+ default_domainsocket="$withval",
+ default_domainsocket="")
+
+if test x$enable_domainsocket != xno -a x$default_domainsocket != xno; then
+ if test "x$default_domainsocket" = x; then
+ case "$uname" in
+ Darwin*)
+ # Darwin and MaxOS X do their own thing...
+ CUPS_DEFAULT_DOMAINSOCKET="$localstatedir/run/cupsd"
+ ;;
+ *)
+ # All others use FHS standard...
+ CUPS_DEFAULT_DOMAINSOCKET="$CUPS_STATEDIR/cups.sock"
+ ;;
+ esac
+ else
+ CUPS_DEFAULT_DOMAINSOCKET="$default_domainsocket"
+ fi
+
+ CUPS_LISTEN_DOMAINSOCKET="Listen $CUPS_DEFAULT_DOMAINSOCKET"
+
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_DOMAINSOCKET, "$CUPS_DEFAULT_DOMAINSOCKET")
+else
+ CUPS_LISTEN_DOMAINSOCKET=""
+fi
+
+AC_SUBST(CUPS_DEFAULT_DOMAINSOCKET)
+AC_SUBST(CUPS_LISTEN_DOMAINSOCKET)
+
+dnl
+dnl End of "$Id: cups-network.m4 4873 2005-12-07 01:46:54Z mike $".
+dnl
diff --git a/config-scripts/cups-opsys.m4 b/config-scripts/cups-opsys.m4
new file mode 100644
index 000000000..5b2b1502c
--- /dev/null
+++ b/config-scripts/cups-opsys.m4
@@ -0,0 +1,99 @@
+dnl
+dnl "$Id: cups-opsys.m4 4833 2005-11-12 21:46:52Z mike $"
+dnl
+dnl Operating system stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl Get the operating system and version number...
+uname=`uname`
+uversion=`uname -r | sed -e '1,$s/[[^0-9]]//g'`
+case "$uname" in
+ GNU* | GNU/*)
+ uname="GNU"
+ ;;
+ IRIX*)
+ uname="IRIX"
+ ;;
+ Linux*)
+ uname="Linux"
+ ;;
+esac
+
+dnl Determine the correct username and group for this OS...
+AC_ARG_WITH(cups-user, [ --with-cups-user set default user for CUPS],
+ CUPS_USER="$withval",
+ AC_MSG_CHECKING(for default print user)
+ if test -f /etc/passwd; then
+ CUPS_USER=""
+ for user in lp lpd guest daemon nobody; do
+ if test "`grep \^${user}: /etc/passwd`" != ""; then
+ CUPS_USER="$user"
+ AC_MSG_RESULT($user)
+ break;
+ fi
+ done
+
+ if test x$CUPS_USER = x; then
+ CUPS_USER="${USER:=nobody}"
+ AC_MSG_RESULT(not found, using "$CUPS_USER")
+ fi
+ else
+ CUPS_USER="${USER:=nobody}"
+ AC_MSG_RESULT(no password file, using "$CUPS_USER")
+ fi)
+
+AC_ARG_WITH(cups-group, [ --with-cups-group set default group for CUPS],
+ CUPS_GROUP="$withval",
+ AC_MSG_CHECKING(for default print group)
+ if test -f /etc/group; then
+ if test x$uname = xDarwin; then
+ GROUP_LIST="lp admin"
+ else
+ GROUP_LIST="lpadmin sys system root"
+ fi
+
+ CUPS_GROUP=""
+ for group in $GROUP_LIST; do
+ if test "`grep \^${group}: /etc/group`" != ""; then
+ CUPS_GROUP="$group"
+ AC_MSG_RESULT($group)
+ break;
+ fi
+ done
+
+ if test x$CUPS_GROUP = x; then
+ CUPS_GROUP="${GROUP:=nobody}"
+ AC_MSG_RESULT(not found, using "$CUPS_GROUP")
+ fi
+ else
+ CUPS_GROUP="${GROUP:=nobody}"
+ AC_MSG_RESULT(no group file, using "$CUPS_GROUP")
+ fi)
+
+AC_SUBST(CUPS_USER)
+AC_SUBST(CUPS_GROUP)
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USER, "$CUPS_USER")
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GROUP, "$CUPS_GROUP")
+
+dnl
+dnl "$Id: cups-opsys.m4 4833 2005-11-12 21:46:52Z mike $"
+dnl
diff --git a/config-scripts/cups-pam.m4 b/config-scripts/cups-pam.m4
new file mode 100644
index 000000000..c86ae292e
--- /dev/null
+++ b/config-scripts/cups-pam.m4
@@ -0,0 +1,98 @@
+dnl
+dnl "$Id: cups-pam.m4 4913 2006-01-11 01:42:04Z mike $"
+dnl
+dnl PAM stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_ARG_ENABLE(pam, [ --enable-pam turn on PAM support, default=yes])
+
+dnl Don't use PAM with AIX...
+if test $uname = AIX; then
+ enable_pam=no
+fi
+
+PAMDIR=""
+PAMFILE=""
+PAMLIBS=""
+PAMMOD="pam_unknown.so"
+
+if test x$enable_pam != xno; then
+ SAVELIBS="$LIBS"
+
+ AC_CHECK_LIB(dl,dlopen)
+ AC_CHECK_LIB(pam,pam_start)
+ AC_CHECK_HEADER(security/pam_appl.h)
+ if test x$ac_cv_header_security_pam_appl_h != xyes; then
+ AC_CHECK_HEADER(pam/pam_appl.h,
+ AC_DEFINE(HAVE_PAM_PAM_APPL_H))
+ fi
+
+ if test x$ac_cv_lib_pam_pam_start != xno; then
+ # Set the necessary libraries for PAM...
+ if test x$ac_cv_lib_dl_dlopen != xno; then
+ PAMLIBS="-lpam -ldl"
+ else
+ PAMLIBS="-lpam"
+ fi
+
+ # Find the PAM configuration directory, if any...
+ for dir in /private/etc/pam.d /etc/pam.d; do
+ if test -d $dir; then
+ PAMDIR=$dir
+ break;
+ fi
+ done
+ fi
+
+ LIBS="$SAVELIBS"
+
+ case "$uname" in
+ Darwin*)
+ # Darwin, MacOS X
+ PAMFILE="pam.darwin"
+ ;;
+ IRIX)
+ # SGI IRIX
+ PAMFILE="pam.irix"
+ ;;
+ *)
+ # All others; this test might need to be updated
+ # as Linux distributors move things around...
+ for mod in pam_unix2.so pam_unix.so pam_pwdb.so; do
+ if test -f /lib/security/$mod; then
+ PAMMOD="$mod"
+ break;
+ fi
+ done
+
+ PAMFILE="pam.std"
+ ;;
+ esac
+fi
+
+AC_SUBST(PAMDIR)
+AC_SUBST(PAMFILE)
+AC_SUBST(PAMLIBS)
+AC_SUBST(PAMMOD)
+
+dnl
+dnl End of "$Id: cups-pam.m4 4913 2006-01-11 01:42:04Z mike $".
+dnl
diff --git a/config-scripts/cups-scripting.m4 b/config-scripts/cups-scripting.m4
new file mode 100644
index 000000000..e0c6832c6
--- /dev/null
+++ b/config-scripts/cups-scripting.m4
@@ -0,0 +1,91 @@
+dnl
+dnl "$Id: cups-scripting.m4 4494 2005-02-18 02:18:11Z mike $"
+dnl
+dnl Scripting configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+dnl Do we have Java?
+AC_ARG_WITH(java, [ --with-java set Java interpreter for web interfaces ],
+ CUPS_JAVA="$withval",
+ CUPS_JAVA="")
+
+if test "x$CUPS_JAVA" = x; then
+ AC_PATH_PROG(JAVA,java)
+ CUPS_JAVA="$JAVA"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_JAVA, "$CUPS_JAVA")
+
+if test "x$CUPS_JAVA" != x; then
+ AC_DEFINE(HAVE_JAVA)
+fi
+
+dnl Do we have Perl?
+AC_ARG_WITH(perl, [ --with-perl set Perl interpreter for web interfaces ],
+ CUPS_PERL="$withval",
+ CUPS_PERL="")
+
+if test "x$CUPS_PERL" = x; then
+ AC_PATH_PROG(PERL,perl)
+ CUPS_PERL="$PERL"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_PERL, "$CUPS_PERL")
+
+if test "x$CUPS_PERL" != x; then
+ AC_DEFINE(HAVE_PERL)
+fi
+
+dnl Do we have PHP?
+AC_ARG_WITH(php, [ --with-php set PHP interpreter for web interfaces ],
+ CUPS_PHP="$withval",
+ CUPS_PHP="")
+
+if test "x$CUPS_PHP" = x; then
+ AC_PATH_PROG(PHP,php)
+ CUPS_PHP="$PHP"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_PHP, "$CUPS_PHP")
+
+if test "x$CUPS_PHP" != x; then
+ AC_DEFINE(HAVE_PHP)
+fi
+
+dnl Do we have Python?
+AC_ARG_WITH(python, [ --with-python set Python interpreter for web interfaces ],
+ CUPS_PYTHON="$withval",
+ CUPS_PYTHON="")
+
+if test "x$CUPS_PYTHON" = x; then
+ AC_PATH_PROG(PYTHON,python)
+ CUPS_PYTHON="$PYTHON"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_PYTHON, "$CUPS_PYTHON")
+
+if test "x$CUPS_PYTHON" != x; then
+ AC_DEFINE(HAVE_PYTHON)
+fi
+
+dnl
+dnl End of "$Id: cups-scripting.m4 4494 2005-02-18 02:18:11Z mike $".
+dnl
diff --git a/config-scripts/cups-sharedlibs.m4 b/config-scripts/cups-sharedlibs.m4
new file mode 100644
index 000000000..8e015a5d7
--- /dev/null
+++ b/config-scripts/cups-sharedlibs.m4
@@ -0,0 +1,156 @@
+dnl
+dnl "$Id: cups-sharedlibs.m4 4800 2005-10-18 18:06:20Z mike $"
+dnl
+dnl Shared library support for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+PICFLAG=1
+DSOFLAGS="${DSOFLAGS:=}"
+
+AC_ARG_ENABLE(shared, [ --enable-shared turn on shared libraries, default=yes])
+
+if test x$enable_shared != xno; 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 \$@"
+ ;;
+ IRIX)
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-rpath,\$(libdir),-set_version,sgi2.6,-soname,\$@ -shared \$(OPTIM)"
+ ;;
+ OSF1* | Linux | GNU | *BSD*)
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)"
+ ;;
+ Darwin*)
+ LIBCUPS="libcups.2.dylib"
+ LIBCUPSIMAGE="libcupsimage.2.dylib"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS \$(RC_CFLAGS) -dynamiclib -lc"
+ ;;
+ AIX*)
+ LIBCUPS="libcups_s.a"
+ LIBCUPSIMAGE="libcupsimage_s.a"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-bexpall,-bM:SRE,-bnoentry,-blibpath:\$(libdir)"
+ ;;
+ *)
+ 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
+
+AC_SUBST(DSO)
+AC_SUBST(DSOFLAGS)
+AC_SUBST(LIBCUPS)
+AC_SUBST(LIBCUPSIMAGE)
+
+if test x$enable_shared = xno; then
+ LINKCUPS="../cups/libcups.a"
+ LINKCUPSIMAGE="../filter/libcupsimage.a"
+else
+ if test $uname = AIX; then
+ LINKCUPS="-lcups_s"
+ LINKCUPSIMAGE="-lcupsimage_s"
+ else
+ LINKCUPS="-lcups"
+ LINKCUPSIMAGE="-lcupsimage"
+ fi
+fi
+
+AC_SUBST(LINKCUPS)
+AC_SUBST(LINKCUPSIMAGE)
+
+dnl Update libraries for DSOs...
+EXPORT_LDFLAGS=""
+
+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="+s +b $libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,+s,+b,$libdir"
+ EXPORT_LDFLAGS="-Wl,+s,+b,$libdir"
+ ;;
+ SunOS*)
+ # Solaris
+ DSOFLAGS="-R$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -R$libdir"
+ EXPORT_LDFLAGS="-R$libdir"
+ ;;
+ *BSD*)
+ # *BSD
+ DSOFLAGS="-Wl,-R$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-R$libdir"
+ EXPORT_LDFLAGS="-Wl,-R$libdir"
+ ;;
+ Linux | GNU)
+ # Linux and HURD
+ DSOFLAGS="-Wl,-rpath,$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-rpath,$libdir"
+ EXPORT_LDFLAGS="-Wl,-rpath,$libdir"
+ ;;
+ esac
+else
+ DSOLIBS=""
+ IMGLIBS="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)"
+fi
+
+AC_SUBST(DSOLIBS)
+AC_SUBST(IMGLIBS)
+AC_SUBST(EXPORT_LDFLAGS)
+
+dnl
+dnl End of "$Id: cups-sharedlibs.m4 4800 2005-10-18 18:06:20Z mike $".
+dnl
diff --git a/config-scripts/cups-slp.m4 b/config-scripts/cups-slp.m4
new file mode 100644
index 000000000..1b32e009d
--- /dev/null
+++ b/config-scripts/cups-slp.m4
@@ -0,0 +1,48 @@
+dnl
+dnl "$Id: cups-openslp.m4 4494 2005-02-18 02:18:11Z mike $"
+dnl
+dnl OpenSLP configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_ARG_ENABLE(slp, [ --enable-slp turn on SLP support, default=yes])
+AC_ARG_WITH(openslp-libs, [ --with-openslp-libs set directory for OpenSLP library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(openslp-includes, [ --with-openslp-includes set directory for OpenSLP includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CXXFLAGS="-I$withval $CXXFLAGS"
+ CPPFLAGS="-I$withval $CPPFLAGS",)
+
+LIBSLP=""
+
+if test x$enable_slp != xno; then
+ AC_CHECK_HEADER(slp.h,
+ AC_CHECK_LIB(slp, SLPOpen,
+ AC_DEFINE(HAVE_LIBSLP)
+ LIBSLP="-lslp"))
+fi
+
+AC_SUBST(LIBSLP)
+
+
+dnl
+dnl End of "$Id: cups-openslp.m4 4494 2005-02-18 02:18:11Z mike $".
+dnl
diff --git a/config-scripts/cups-ssl.m4 b/config-scripts/cups-ssl.m4
new file mode 100644
index 000000000..166ca5897
--- /dev/null
+++ b/config-scripts/cups-ssl.m4
@@ -0,0 +1,109 @@
+dnl
+dnl "$Id: cups-ssl.m4 4800 2005-10-18 18:06:20Z mike $"
+dnl
+dnl OpenSSL/GNUTLS stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_ARG_ENABLE(ssl, [ --enable-ssl turn on SSL/TLS support, default=yes])
+AC_ARG_ENABLE(cdsassl, [ --enable-cdsassl use CDSA for SSL/TLS support, default=first])
+AC_ARG_ENABLE(gnutls, [ --enable-gnutls use GNU TLS for SSL/TLS support, default=second])
+AC_ARG_ENABLE(openssl, [ --enable-openssl use OpenSSL for SSL/TLS support, default=third])
+AC_ARG_WITH(openssl-libs, [ --with-openssl-libs set directory for OpenSSL library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(openssl-includes, [ --with-openssl-includes set directory for OpenSSL includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CXXFLAGS="-I$withval $CXXFLAGS"
+ CPPFLAGS="-I$withval $CPPFLAGS",)
+
+SSLFLAGS=""
+SSLLIBS=""
+
+if test x$enable_ssl != xno; then
+ dnl Look for CDSA...
+ if test "x${SSLLIBS}" = "x" -a "x${enable_cdsassl}" != "xno"; then
+ if test $uname = Darwin; then
+ AC_CHECK_HEADER(Security/SecureTransport.h,
+ [SSLLIBS="-framework CoreFoundation -framework Security"
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_CDSASSL)])
+ fi
+ fi
+
+ dnl Then look for GNU TLS...
+ if test "x${SSLLIBS}" = "x" -a "x${enable_gnutls}" != "xno"; then
+ AC_CHECK_HEADER(gnutls/gnutls.h,
+ dnl Save the current libraries so the crypto stuff isn't always
+ dnl included...
+ SAVELIBS="$LIBS"
+
+ AC_CHECK_LIB(gnutls, gnutls_init,
+ [SSLLIBS="-lgnutls"
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_GNUTLS)])
+
+ LIBS="$SAVELIBS")
+ fi
+
+ dnl Check for the OpenSSL library last...
+ if test "x${SSLLIBS}" = "x" -a "x${enable_openssl}" != "xno"; then
+ AC_CHECK_HEADER(openssl/ssl.h,
+ 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,
+ [SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT"
+ SSLLIBS="-lssl $libcrypto"
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_LIBSSL)],,
+ $libcrypto)
+
+ if test "x${SSLLIBS}" != "x"; then
+ break
+ fi
+ done
+
+ LIBS="$SAVELIBS")
+ fi
+fi
+
+AC_SUBST(SSLFLAGS)
+AC_SUBST(SSLLIBS)
+
+EXPORT_SSLLIBS="$SSLLIBS"
+AC_SUBST(EXPORT_SSLLIBS)
+
+
+dnl
+dnl End of "$Id: cups-ssl.m4 4800 2005-10-18 18:06:20Z mike $".
+dnl
diff --git a/config-scripts/cups-threads.m4 b/config-scripts/cups-threads.m4
new file mode 100644
index 000000000..788ce838c
--- /dev/null
+++ b/config-scripts/cups-threads.m4
@@ -0,0 +1,51 @@
+dnl
+dnl "$Id$"
+dnl
+dnl Threading stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_ARG_ENABLE(threads, [ --enable-threads enable multi-threading support])
+
+have_pthread=no
+
+if test "x$enable_threads" != xno; then
+ AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H))
+ AC_CHECK_LIB(pthread, pthread_create)
+
+ if test "x$ac_cv_lib_pthread_pthread_create" = xyes -a x$ac_cv_header_pthread_h = xyes; then
+ have_pthread=yes
+ else
+ dnl *BSD uses -pthread option...
+ AC_MSG_CHECKING([for pthread_create using -pthread])
+ SAVELIBS="$LIBS"
+ LIBS="-pthread $LIBS"
+ AC_TRY_LINK([#include ],
+ [pthread_create(0, 0, 0, 0);],
+ have_pthread=yes,
+ LIBS="$SAVELIBS")
+ AC_MSG_RESULT([$have_pthread])
+ fi
+fi
+
+
+dnl
+dnl End of "$Id$".
+dnl
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 000000000..9b853da17
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,343 @@
+/*
+ * "$Id: config.h.in 4760 2005-10-08 20:11:08Z mike $"
+ *
+ * Configuration file for the Common UNIX Printing System (CUPS).
+ *
+ * @configure_input@
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+#ifndef _CUPS_CONFIG_H_
+#define _CUPS_CONFIG_H_
+
+/*
+ * Version of software...
+ */
+
+#define CUPS_SVERSION ""
+#define CUPS_MINIMAL ""
+
+
+/*
+ * Default user and group...
+ */
+
+#define CUPS_DEFAULT_USER "lp"
+#define CUPS_DEFAULT_GROUP "sys"
+
+
+/*
+ * Default IPP port...
+ */
+
+#define CUPS_DEFAULT_IPP_PORT 631
+
+
+/*
+ * Maximum number of file descriptors to support.
+ */
+
+#define CUPS_MAX_FDS 4096
+
+
+/*
+ * Do we have domain socket support?
+ */
+
+#undef CUPS_DEFAULT_DOMAINSOCKET
+
+
+/*
+ * Where are files stored?
+ *
+ * Note: These are defaults, which can be overridden by environment
+ * variables at run-time...
+ */
+
+#define CUPS_CACHEDIR "/var/cache/cups"
+#define CUPS_DATADIR "/usr/share/cups"
+#define CUPS_DOCROOT "/usr/share/doc/cups"
+#define CUPS_FONTPATH "/usr/share/cups/fonts"
+#define CUPS_LOCALEDIR "/usr/share/locale"
+#define CUPS_LOGDIR "/var/logs/cups"
+#define CUPS_REQUESTS "/var/spool/cups"
+#define CUPS_SERVERBIN "/usr/lib/cups"
+#define CUPS_SERVERROOT "/etc/cups"
+#define CUPS_STATEDIR "/var/run/cups"
+
+
+/*
+ * Do we have various image libraries?
+ */
+
+#undef HAVE_LIBPNG
+#undef HAVE_LIBZ
+#undef HAVE_LIBJPEG
+#undef HAVE_LIBTIFF
+
+
+/*
+ * Do we have PAM stuff?
+ */
+
+#ifndef HAVE_LIBPAM
+#define HAVE_LIBPAM 0
+#endif /* !HAVE_LIBPAM */
+
+#undef HAVE_PAM_PAM_APPL_H
+
+
+/*
+ * Do we have ?
+ */
+
+#undef HAVE_SHADOW_H
+
+
+/*
+ * Do we have ?
+ */
+
+#undef HAVE_CRYPT_H
+
+
+/*
+ * Use , , and/or ?
+ */
+
+#undef HAVE_STRING_H
+#undef HAVE_STRINGS_H
+#undef HAVE_BSTRING_H
+
+/*
+ * Do we have the long long type?
+ */
+
+#undef HAVE_LONG_LONG
+
+#ifdef HAVE_LONG_LONG
+# define CUPS_LLFMT "%lld"
+# define CUPS_LLCAST (long long)
+#else
+# define CUPS_LLFMT "%ld"
+# define CUPS_LLCAST (long)
+#endif /* HAVE_LONG_LONG */
+
+/*
+ * Do we have the strtoll() function?
+ */
+
+#undef HAVE_STRTOLL
+
+#ifndef HAVE_STRTOLL
+# define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base))
+#endif /* !HAVE_STRTOLL */
+
+/*
+ * Do we have the strXXX() functions?
+ */
+
+#undef HAVE_STRDUP
+#undef HAVE_STRCASECMP
+#undef HAVE_STRNCASECMP
+#undef HAVE_STRLCAT
+#undef HAVE_STRLCPY
+
+
+/*
+ * Do we have the geteuid() function?
+ */
+
+#undef HAVE_GETEUID
+
+
+/*
+ * 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 langinfo.h header file?
+ */
+
+#undef HAVE_LANGINFO_H
+
+
+/*
+ * Which encryption libraries do we have?
+ */
+
+#undef HAVE_CDSASSL
+#undef HAVE_GNUTLS
+#undef HAVE_LIBSSL
+#undef HAVE_SSL
+
+
+/*
+ * Do we have the OpenSLP library?
+ */
+
+#undef HAVE_LIBSLP
+
+
+/*
+ * Do we have libpaper?
+ */
+
+#undef HAVE_LIBPAPER
+
+
+/*
+ * Do we have ?
+ */
+
+#undef HAVE_SYS_IOCTL_H
+
+
+/*
+ * Do we have mkstemp() and/or mkstemps()?
+ */
+
+#undef HAVE_MKSTEMP
+#undef HAVE_MKSTEMPS
+
+
+/*
+ * Does the "tm" structure contain the "tm_gmtoff" member?
+ */
+
+#undef HAVE_TM_GMTOFF
+
+
+/*
+ * Do we have rresvport_af()?
+ */
+
+#undef HAVE_RRESVPORT_AF
+
+
+/*
+ * Do we have getaddrinfo()?
+ */
+
+#undef HAVE_GETADDRINFO
+
+
+/*
+ * Do we have getnameinfo()?
+ */
+
+#undef HAVE_GETNAMEINFO
+
+
+/*
+ * Do we have getifaddrs()?
+ */
+
+#undef HAVE_GETIFADDRS
+
+
+/*
+ * Do we have hstrerror()?
+ */
+
+#undef HAVE_HSTRERROR
+
+
+/*
+ * Do we have the header file?
+ */
+
+#undef HAVE_SYS_SOCKIO_H
+
+
+/*
+ * Does the sockaddr structure contain an sa_len parameter?
+ */
+
+#undef HAVE_STRUCT_SOCKADDR_SA_LEN
+
+
+/*
+ * Do we have the AIX usersec.h header file?
+ */
+
+#undef HAVE_USERSEC_H
+
+/*
+ * Do we have pthread support?
+ */
+
+#undef HAVE_PTHREAD_H
+
+
+/*
+ * Various scripting languages...
+ */
+
+#undef HAVE_JAVA
+#define CUPS_JAVA "/usr/bin/java"
+#undef HAVE_PERL
+#define CUPS_PERL "/usr/bin/perl"
+#undef HAVE_PHP
+#define CUPS_PHP "/usr/bin/php"
+#undef HAVE_PYTHON
+#define CUPS_PYTHON "/usr/bin/python"
+
+
+#endif /* !_CUPS_CONFIG_H_ */
+
+/*
+ * End of "$Id: config.h.in 4760 2005-10-08 20:11:08Z mike $".
+ */
diff --git a/configure.in b/configure.in
new file mode 100644
index 000000000..2057cd5f9
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,57 @@
+dnl
+dnl "$Id: configure.in 4873 2005-12-07 01:46:54Z mike $"
+dnl
+dnl Configuration script for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2005 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 USA
+dnl
+dnl Voice: (301) 373-9600
+dnl EMail: cups-info@cups.org
+dnl WWW: http://www.cups.org
+dnl
+
+AC_INIT(cups/cups.h)
+
+sinclude(config-scripts/cups-opsys.m4)
+sinclude(config-scripts/cups-common.m4)
+sinclude(config-scripts/cups-directories.m4)
+sinclude(config-scripts/cups-manpages.m4)
+
+sinclude(config-scripts/cups-sharedlibs.m4)
+sinclude(config-scripts/cups-libtool.m4)
+sinclude(config-scripts/cups-compiler.m4)
+
+sinclude(config-scripts/cups-image.m4)
+sinclude(config-scripts/cups-network.m4)
+sinclude(config-scripts/cups-slp.m4)
+sinclude(config-scripts/cups-ssl.m4)
+sinclude(config-scripts/cups-pam.m4)
+sinclude(config-scripts/cups-threads.m4)
+sinclude(config-scripts/cups-largefile.m4)
+
+MAKEDEFS="../Makedefs"
+AC_SUBST(MAKEDEFS)
+
+sinclude(config-scripts/cups-scripting.m4)
+
+AC_OUTPUT(Makedefs packaging/cups.list cups.sh cups-config
+ conf/cupsd.conf conf/pam.std doc/index.html
+ doc/help/standard.html templates/edit-config.tmpl)
+
+chmod +x cups-config
+
+dnl
+dnl End of "$Id: configure.in 4873 2005-12-07 01:46:54Z mike $".
+dnl
diff --git a/cups-config.in b/cups-config.in
new file mode 100755
index 000000000..fdea47ea2
--- /dev/null
+++ b/cups-config.in
@@ -0,0 +1,134 @@
+#! /bin/sh
+#
+# "$Id: cups-config.in 4802 2005-10-19 13:48:06Z mike $"
+#
+# CUPS configuration utility.
+#
+# Copyright 2001-2005 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+VERSION="@CUPS_VERSION@"
+APIVERSION="1.2"
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+includedir=@includedir@
+libdir=@libdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+cups_datadir=@CUPS_DATADIR@
+cups_serverbin=@CUPS_SERVERBIN@
+cups_serverroot=@CUPS_SERVERROOT@
+
+# flags for C++ compiler:
+CFLAGS=""
+LDFLAGS="@EXPORT_LDFLAGS@"
+LIBS="@EXPORT_SSLLIBS@ @LIBS@"
+IMGLIBS="@EXPORT_LIBTIFF@ @EXPORT_LIBJPEG@ @EXPORT_LIBPNG@ @EXPORT_LIBZ@"
+
+if test $includedir != /usr/include; then
+ CFLAGS="$CFLAGS -I$includedir"
+fi
+
+if test $libdir != /usr/lib -a $libdir != /usr/lib32; then
+ LDFLAGS="$LDFLAGS -L$libdir"
+fi
+
+usage ()
+{
+ echo "Usage: cups-config --api-version"
+ echo " cups-config --cflags"
+ echo " cups-config --datadir"
+ echo " cups-config --help"
+ echo " cups-config --ldflags"
+ echo " cups-config [--image] [--static] --libs"
+ echo " cups-config --serverbin"
+ echo " cups-config --serverroot"
+ echo " cups-config --version"
+
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1
+fi
+
+# Parse command line options
+static=no
+image=no
+
+while test $# -gt 0; do
+ case $1 in
+ --api-version)
+ echo $APIVERSION
+ ;;
+ --cflags)
+ echo $CFLAGS
+ ;;
+ --datadir)
+ echo $cups_datadir
+ ;;
+ --help)
+ usage 0
+ ;;
+ --image)
+ image=yes
+ ;;
+ --ldflags)
+ echo $LDFLAGS
+ ;;
+ --libs)
+ if test $static = no; then
+ if test $image = no; then
+ echo -lcups $LIBS
+ else
+ echo -lcupsimage $IMGLIBS -lcups $LIBS
+ fi
+ else
+ if test $image = no; then
+ echo $libdir/libcups.a $LIBS
+ else
+ echo $libdir/libcupsimage.a $IMGLIBS $libdir/libcups.a $LIBS
+ fi
+ fi
+ ;;
+ --serverbin)
+ echo $cups_serverbin
+ ;;
+ --serverroot)
+ echo $cups_serverroot
+ ;;
+ --static)
+ static=yes
+ ;;
+ --version)
+ echo $VERSION
+ ;;
+ *)
+ usage 1
+ ;;
+ esac
+
+ shift
+done
+
+#
+# End of "$Id: cups-config.in 4802 2005-10-19 13:48:06Z mike $".
+#
diff --git a/cups.osx b/cups.osx
new file mode 100644
index 000000000..bff65dcc6
--- /dev/null
+++ b/cups.osx
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+##
+# PrintingServices - a.k.a. CUPS
+##
+
+. /etc/rc.common
+
+StartService ()
+{
+ if [ "${CUPS:=-YES-}" = "-YES-" ]; then
+ ConsoleMessage "Starting printing services"
+ /usr/sbin/cupsd
+ fi
+}
+
+StopService ()
+{
+ # Until cupsd has a pid file...
+ pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'`
+ if test "$pid" != ""; then
+ ConsoleMessage "Stopping printing services"
+ kill "${pid}"
+ fi
+}
+
+RestartService ()
+{
+ # Until cupsd has a pid file...
+ pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'`
+ if test "x$pid" != x; then
+ ConsoleMessage "Restarting printing services"
+ kill -HUP "${pid}"
+ else
+ StartService
+ fi
+}
+
+RunService "$1"
diff --git a/cups.plist b/cups.plist
new file mode 100644
index 000000000..0633bf88a
--- /dev/null
+++ b/cups.plist
@@ -0,0 +1,7 @@
+{
+ Description = "Printing Services";
+ Provides = ("PrintingServices");
+ Requires = ("Resolver");
+ Uses = ("Network Time");
+ OrderPreference = "Late";
+}
diff --git a/cups.sh.in b/cups.sh.in
new file mode 100755
index 000000000..bba1d4428
--- /dev/null
+++ b/cups.sh.in
@@ -0,0 +1,211 @@
+#!/bin/sh
+#
+# "$Id: cups.sh.in 4493 2005-02-18 02:09:53Z mike $"
+#
+# Startup/shutdown script for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2005 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+#### OS-Dependent Information
+
+#
+# Linux chkconfig stuff:
+#
+# chkconfig: 235 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
+
+ if $IS_ON verbose; then
+ ECHO=echo
+ else
+ ECHO=:
+ fi
+ ECHO_OK=:
+ ECHO_ERROR=:
+ ;;
+
+ *BSD*)
+ IS_ON=:
+ ECHO=echo
+ ECHO_OK=:
+ ECHO_ERROR=:
+ ;;
+
+ Darwin*)
+ . /etc/rc.common
+
+ if test "${CUPS:=-YES-}" = "-NO-"; then
+ exit 0
+ fi
+
+ IS_ON=:
+ ECHO=ConsoleMessage
+ ECHO_OK=:
+ ECHO_ERROR=:
+ ;;
+
+ Linux*)
+ IS_ON=/bin/true
+ if test -f /etc/init.d/functions; then
+ . /etc/init.d/functions
+ ECHO=echo
+ ECHO_OK="echo_success"
+ ECHO_ERROR="echo_failure"
+ else
+ ECHO=echo
+ ECHO_OK=:
+ ECHO_ERROR=:
+ fi
+ ;;
+
+ *)
+ IS_ON=/bin/true
+ ECHO=echo
+ ECHO_OK=:
+ ECHO_ERROR=:
+ ;;
+esac
+
+#### OS-Independent Stuff
+
+#
+# Set the timezone, if possible... This allows the
+# scheduler and all child processes to know the local
+# timezone when reporting dates and times to the user.
+# If no timezone information is found, then Greenwich
+# Mean Time (GMT) will probably be used.
+#
+
+for file in /etc/TIMEZONE /etc/rc.config /etc/sysconfig/clock; do
+ if test -f $file; then
+ . $file
+ fi
+done
+
+if test "x$ZONE" != x; then
+ TZ="$ZONE"
+fi
+
+if test "x$TIMEZONE" != x; then
+ TZ="$TIMEZONE"
+fi
+
+if test "x$TZ" != x; then
+ export TZ
+fi
+
+#
+# See if the CUPS server (cupsd) is running...
+#
+
+case "`uname`" in
+ HP-UX* | AIX* | SINIX*)
+ pid=`ps -e | awk '{if (match($4, ".*/cupsd$") || $4 == "cupsd") print $1}'`
+ ;;
+ IRIX* | SunOS*)
+ pid=`ps -e | nawk '{if (match($4, ".*/cupsd$") || $4 == "cupsd") print $1}'`
+ ;;
+ UnixWare*)
+ pid=`ps -e | awk '{if (match($6, ".*/cupsd$") || $6 == "cupsd") print $1}'`
+ . /etc/TIMEZONE
+ ;;
+ OSF1*)
+ pid=`ps -e | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'`
+ ;;
+ Linux* | *BSD* | Darwin*)
+ pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") 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
+ if test $? != 0; then
+ $ECHO_FAIL
+ $ECHO "cups: unable to $1 scheduler."
+ exit 1
+ fi
+ fi
+ $ECHO_OK
+ $ECHO "cups: ${1}ed scheduler."
+ fi
+ ;;
+
+ stop)
+ if test "$pid" != ""; then
+ kill $pid
+ $ECHO_OK
+ $ECHO "cups: stopped scheduler."
+ 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: cups.sh.in 4493 2005-02-18 02:09:53Z mike $".
+#
diff --git a/cups.strings b/cups.strings
new file mode 100644
index 000000000..d08f91972
--- /dev/null
+++ b/cups.strings
@@ -0,0 +1,9 @@
+
+
+
+
+ Starting printing services
+ Starting printing services
+
+
+
diff --git a/cups/Dependencies b/cups/Dependencies
new file mode 100644
index 000000000..8b3a12288
--- /dev/null
+++ b/cups/Dependencies
@@ -0,0 +1,66 @@
+# DO NOT DELETE
+
+array.o: array.h string.h ../config.h debug.h
+attr.o: ppd.h file.h debug.h string.h ../config.h
+auth.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h
+auth.o: i18n.h language.h array.h normalize.h transcode.h debug.h
+backchannel.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h
+dest.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h
+dest.o: i18n.h language.h array.h normalize.h transcode.h
+dir.o: dir.h string.h ../config.h debug.h
+emit.o: ppd.h file.h string.h ../config.h
+encode.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h debug.h
+file.o: http-private.h ../config.h http.h string.h md5.h ../cups/debug.h
+file.o: file.h
+getputfile.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h
+getputfile.o: language.h array.h debug.h
+globals.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h
+globals.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h
+globals.o: transcode.h
+http.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h
+http.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h transcode.h
+http.o: debug.h
+http-addr.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+http-addr.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h
+http-addrlist.o: http-private.h ../config.h http.h string.h md5.h globals.h
+http-addrlist.o: cups.h ipp.h ppd.h file.h i18n.h language.h array.h
+http-addrlist.o: normalize.h transcode.h debug.h
+http-support.o: debug.h globals.h string.h ../config.h cups.h ipp.h http.h
+http-support.o: md5.h ppd.h file.h i18n.h language.h array.h normalize.h
+http-support.o: transcode.h
+ipp.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h
+ipp.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h transcode.h
+ipp.o: debug.h
+ipp-support.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+ipp-support.o: file.h i18n.h language.h array.h normalize.h transcode.h
+ipp-support.o: debug.h
+langprintf.o: string.h ../config.h i18n.h language.h array.h transcode.h
+language.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+language.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h
+mark.o: ppd.h file.h string.h ../config.h debug.h
+md5.o: md5.h string.h ../config.h
+md5passwd.o: http.h string.h ../config.h md5.h
+normalize.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+normalize.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h
+options.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h
+options.o: debug.h
+page.o: ppd.h file.h string.h ../config.h
+ppd.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h
+ppd.o: i18n.h language.h array.h normalize.h transcode.h debug.h
+snprintf.o: string.h ../config.h
+string.o: string.h ../config.h
+tempfile.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+tempfile.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h
+transcode.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h
+transcode.o: file.h i18n.h language.h array.h normalize.h transcode.h
+usersys.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h
+usersys.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h
+usersys.o: transcode.h
+util.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h
+util.o: i18n.h language.h array.h normalize.h transcode.h debug.h
+testarray.o: ../cups/string.h ../config.h string.h array.h dir.h debug.h
+testfile.o: string.h ../config.h file.h debug.h
+testhttp.o: http.h string.h ../config.h md5.h
+testi18n.o: language.h array.h string.h ../config.h transcode.h normalize.h
+testipp.o: ../cups/string.h ../config.h string.h ipp.h http.h md5.h
+testlang.o: i18n.h language.h array.h
diff --git a/cups/Makefile b/cups/Makefile
new file mode 100644
index 000000000..1834c1312
--- /dev/null
+++ b/cups/Makefile
@@ -0,0 +1,342 @@
+#
+# "$Id: Makefile 4918 2006-01-12 05:14:40Z mike $"
+#
+# API library Makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2006 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 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+#
+# Object files...
+#
+
+LIBOBJS = \
+ array.o \
+ attr.o \
+ auth.o \
+ backchannel.o \
+ dest.o \
+ dir.o \
+ emit.o \
+ encode.o \
+ file.o \
+ getputfile.o \
+ globals.o \
+ http.o \
+ http-addr.o \
+ http-addrlist.o \
+ http-support.o \
+ ipp.o \
+ ipp-support.o \
+ langprintf.o \
+ language.o \
+ mark.o \
+ md5.o \
+ md5passwd.o \
+ normalize.o \
+ options.o \
+ page.o \
+ ppd.o \
+ snprintf.o \
+ string.o \
+ tempfile.o \
+ transcode.o \
+ usersys.o \
+ util.o
+OBJS = \
+ $(LIBOBJS) \
+ testarray.o \
+ testfile.o \
+ testhttp.o \
+ testi18n.o \
+ testipp.o \
+ testlang.o \
+ php_cups_wrap.o
+
+
+#
+# Header files to install...
+#
+
+HEADERS = \
+ array.h \
+ cups.h \
+ dir.h \
+ file.h \
+ http.h \
+ i18n.h \
+ ipp.h \
+ language.h \
+ md5.h \
+ normalize.h \
+ ppd.h \
+ transcode.h
+
+
+#
+# Targets in this directory...
+#
+
+TARGETS = \
+ $(LIBCUPS) \
+ libcups.a \
+ testarray \
+ testfile \
+ testhttp \
+ testi18n \
+ testipp \
+ testlang
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Remove object and target files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) `basename $(LIBCUPS) .2` libcups.dylib
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install object and target files...
+#
+
+install: all installhdrs
+ $(INSTALL_DIR) $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPS) $(LIBDIR)
+ if test $(LIBCUPS) = "libcups.so.2" -o $(LIBCUPS) = "libcups.sl.2"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPS) .2`; \
+ $(LN) $(LIBCUPS) $(LIBDIR)/`basename $(LIBCUPS) .2`; \
+ fi
+ if test $(LIBCUPS) = "libcups.2.dylib"; then \
+ $(STRIP) -x $(LIBDIR)/$(LIBCUPS); \
+ $(RM) $(LIBDIR)/libcups.dylib; \
+ $(LN) $(LIBCUPS) $(LIBDIR)/libcups.dylib; \
+ fi
+ if test $(LIBCUPS) != "libcups.a"; then \
+ $(INSTALL_LIB) libcups.a $(LIBDIR); \
+ $(RANLIB) $(LIBDIR)/libcups.a; \
+ fi
+
+installhdrs:
+ $(INSTALL_DIR) $(INCLUDEDIR)/cups
+ for file in $(HEADERS); do \
+ $(INSTALL_DATA) $$file $(INCLUDEDIR)/cups; \
+ done
+
+
+#
+# libcups.so.2, libcups.sl.2
+#
+
+libcups.so.2 libcups.sl.2: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(RM) `basename $@ .2`
+ $(LN) $@ `basename $@ .2`
+
+
+#
+# libcups.2.dylib
+#
+
+libcups.2.dylib: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/libcups.dylib \
+ -current_version 2.7.0 \
+ -compatibility_version 2.0.0 \
+ $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(RM) libcups.dylib
+ $(LN) $@ libcups.dylib
+
+
+#
+# libcups_s.a
+#
+
+libcups_s.a: $(LIBOBJS)
+ echo Creating $@...
+ $(DSO) $(DSOFLAGS) -Wl,-bexport:libcups_s.exp -o libcups_s.o $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcups_s.o
+
+
+#
+# libcups.la
+#
+
+libcups.la: $(LIBOBJS)
+ echo Linking $@...
+ $(CC) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 2:7 $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# libcups.a
+#
+
+libcups.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# CUPS language bindings for various scripting languages...
+#
+
+phpcups.so: $(LIBCUPS) php_cups_wrap.o
+ echo Linking $@...
+ if test `uname` = Darwin; then \
+ DSOFLAGS="-bundle -flat_namespace -undefined suppress"; \
+ else \
+ DSOFLAGS="$(DSOFLAGS)"; \
+ fi; \
+ $(DSO) $$DSOFLAGS -o $@ php_cups_wrap.o $(LIBS) `php-config --ldflags --libs`
+
+php_cups_wrap.o: php_cups_wrap.c
+ echo Compiling $<...
+ $(CC) $(CFLAGS) `php-config --includes` -c $<
+php_cups_wrap.c: cups.h
+ echo Creating $< using SWIG...
+ swig -php -o $@ -module cups cups.h
+
+
+#
+# testarray (dependency on static CUPS library is intentional)
+#
+
+testarray: testarray.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testarray.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testfile (dependency on static CUPS library is intentional)
+#
+
+testfile: testfile.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testfile.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testhttp (dependency on static CUPS library is intentional)
+#
+
+testhttp: testhttp.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testhttp.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testipp (dependency on static CUPS library is intentional)
+#
+
+testipp: testipp.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testipp.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testi18n (dependency on static CUPS library is intentional)
+#
+
+testi18n: testi18n.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testi18n.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testlang (dependency on static CUPS library is intentional)
+#
+
+testlang: testlang.o libcups.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testlang.o libcups.a \
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ echo Generating CUPS API help files...
+ mxmldoc --section "Programming" --title "Array API" \
+ --intro api-array.shtml \
+ array.h array.c >../doc/help/api-array.html
+ mxmldoc --section "Programming" --title "CUPS API" \
+ --intro api-cups.shtml \
+ cups.h auth.c dest.c encode.c getputfile.c language.c \
+ options.c tempfile.c usersys.c \
+ util.c >../doc/help/api-cups.html
+ mxmldoc --section "Programming" --title "File and Directory APIs" \
+ --intro api-filedir.shtml \
+ file.h file.c dir.h dir.c >../doc/help/api-filedir.html
+ mxmldoc --section "Programming" --title "PPD API" \
+ --intro api-ppd.shtml \
+ ppd.h attr.c emit.c mark.c page.c \
+ ppd.c >../doc/help/api-ppd.html
+ mxmldoc --section "Programming" --title "HTTP and IPP APIs" \
+ --intro api-httpipp.shtml \
+ cups.h http.h ipp.h \
+ auth.c dest.c encode.c getputfile.c http.c http-addr.c \
+ http-support.c ipp.c ipp-support.c md5passwd.c options.c \
+ usersys.c util.c >../doc/help/api-httpipp.html
+ mxmldoc --section "Programming" --title "Filter and Backend APIs" \
+ --intro api-filter.shtml \
+ backchannel.c >../doc/help/api-filter.html
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id: Makefile 4918 2006-01-12 05:14:40Z mike $".
+#
diff --git a/cups/api-array.shtml b/cups/api-array.shtml
new file mode 100644
index 000000000..d6297fb6a
--- /dev/null
+++ b/cups/api-array.shtml
@@ -0,0 +1,54 @@
+
+
+Introduction
+
+The CUPS array API provides a high-performance generic array
+container. The contents of the array container can be sorted and
+the container itself is designed for optimal speed and memory
+usage under a wide variety of conditions.
+
+The CUPS scheduler (cupsd) and many of the CUPS API
+functions use the array API to efficiently manage large lists of
+data.
+
+General Usage
+
+The <cups/array.h> header file must be
+included to use the cupsArray functions.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+All of these functions require CUPS 1.2 or higher.
diff --git a/cups/api-cups.shtml b/cups/api-cups.shtml
new file mode 100644
index 000000000..a39112795
--- /dev/null
+++ b/cups/api-cups.shtml
@@ -0,0 +1,48 @@
+
+
+Introduction
+
+The CUPS APIs provide...
+
+General Usage
+
+The <cups/cups.h> header file must be included to
+use the CUPS functions.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+Unless otherwise specified, the CUPS API functions require
+CUPS 1.1 or higher.
diff --git a/cups/api-filedir.shtml b/cups/api-filedir.shtml
new file mode 100644
index 000000000..d321cc604
--- /dev/null
+++ b/cups/api-filedir.shtml
@@ -0,0 +1,66 @@
+
+
+Introduction
+
+The CUPS file and directory APIs provide portable interfaces
+for manipulating files and listing files and directories. Unlike
+stdio FILE streams, the cupsFile functions
+allow you to open more than 256 files at any given time. They
+also manage the platform-specific details of locking, large file
+support, line endings (CR, LF, or CR LF), and reading and writing
+files using Flate ("gzip") compression. Finally, you can also
+connect, read from, and write to network connections using the
+cupsFile functions.
+
+The cupsDir functions manage the platform-specific
+details of directory access/listing and provide a convenient way
+to get both a list of files and the information (permissions,
+size, timestamp, etc.) for each of those files.
+
+The CUPS scheduler (cupsd), mailto notifier,
+and many of the CUPS API functions use these functions for
+everything except console (stdin, stdout, stderr) I/O.
+
+General Usage
+
+The <cups/dir.h> and
+<cups/file.h> header files must be included to
+use the cupsDir and cupsFile functions,
+respectively.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+All of these functions require CUPS 1.2 or higher.
diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml
new file mode 100644
index 000000000..f43a8d140
--- /dev/null
+++ b/cups/api-filter.shtml
@@ -0,0 +1,49 @@
+
+
+Introduction
+
+The CUPS filter and backend APIs provide...
+
+General Usage
+
+The <cups/backend.h> and
+<cups/cups.h> header files must be included to
+use the CUPS_BACKEND_ constants and
+cupsBackchannel functions, respectively.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+All of these functions require CUPS 1.2 or higher.
diff --git a/cups/api-httpipp.shtml b/cups/api-httpipp.shtml
new file mode 100644
index 000000000..1c1b6a43e
--- /dev/null
+++ b/cups/api-httpipp.shtml
@@ -0,0 +1,48 @@
+
+
+Introduction
+
+The CUPS HTTP and IPP APIs provide...
+
+General Usage
+
+The <cups/cups.h> header file must be included to
+use the HTTP and IPP functions.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+Unless otherwise specified, the HTTP and IPP API functions
+require CUPS 1.1 or higher.
diff --git a/cups/api-ppd.shtml b/cups/api-ppd.shtml
new file mode 100644
index 000000000..337ee3d46
--- /dev/null
+++ b/cups/api-ppd.shtml
@@ -0,0 +1,48 @@
+
+
+Introduction
+
+The CUPS PPD API provides...
+
+General Usage
+
+The <cups/ppd.h> header file must be included
+to use the ppd functions.
+
+Programs using these functions must be linked to the CUPS
+library: libcups.a, libcups.so.2,
+libcups.2.dylib, libcups_s.a, or
+libcups2.lib depending on the platform. The following
+command compiles myprogram.c using GCC and the CUPS
+library:
+
+
+gcc -o myprogram myprogram.c -lcups
+
+
+Compatibility
+
+Unless otherwise specified, the PPD API functions require CUPS
+1.1 or higher.
diff --git a/cups/array.c b/cups/array.c
new file mode 100644
index 000000000..88f26cd72
--- /dev/null
+++ b/cups/array.c
@@ -0,0 +1,828 @@
+/*
+ * "$Id: array.c 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Sorted array routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsArrayAdd() - Add an element to the array.
+ * cupsArrayClear() - Clear the array.
+ * cupsArrayCount() - Get the number of elements in the array.
+ * cupsArrayCurrent() - Return the current element in the array.
+ * cupsArrayDelete() - Free all memory used by the array.
+ * cupsArrayDup() - Duplicate the array.
+ * cupsArrayFind() - Find an element in the array.
+ * cupsArrayFirst() - Get the first element in the array.
+ * cupsArrayIndex() - Get the N-th element in the array.
+ * cupsArrayLast() - Get the last element in the array.
+ * cupsArrayNew() - Create a new array.
+ * cupsArrayNext() - Get the next element in the array.
+ * cupsArrayPrev() - Get the previous element in the array.
+ * cupsArrayRemove() - Remove an element from the array.
+ * cupsArrayRestore() - Reset the current element to the last cupsArraySave.
+ * cupsArraySave() - Mark the current element for a later cupsArrayRestore.
+ * cups_find() - Find an element in the array...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "array.h"
+#include "string.h"
+#include "debug.h"
+
+
+/*
+ * Limits...
+ */
+
+#define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/
+
+
+/*
+ * Types and structures...
+ */
+
+struct _cups_array_s /**** CUPS array structure ****/
+{
+ /*
+ * The current implementation uses an insertion sort into an array of
+ * sorted pointers. We leave the array type private/opaque so that we
+ * can change the underlying implementation without affecting the users
+ * of this API.
+ */
+
+ int num_elements, /* Number of array elements */
+ alloc_elements, /* Allocated array elements */
+ current, /* Current element */
+ insert, /* Last inserted element */
+ num_saved, /* Number of saved elements */
+ saved[_CUPS_MAXSAVE];
+ /* Saved elements */
+ void **elements; /* Array elements */
+ cups_array_func_t compare; /* Element comparison function */
+ void *data; /* User data passed to compare */
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_find(cups_array_t *a, void *e, int prev, int *rdiff);
+
+
+/*
+ * 'cupsArrayAdd()' - Add an element to the array.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsArrayAdd(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ int i, /* Looping var */
+ current, /* Current element */
+ diff; /* Comparison with current element */
+
+
+ DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a, e));
+
+ /*
+ * Range check input...
+ */
+
+ if (!a || !e)
+ {
+ DEBUG_puts("cupsArrayAdd: returning 0");
+ return (0);
+ }
+
+ /*
+ * Verify we have room for the new element...
+ */
+
+ if (a->num_elements >= a->alloc_elements)
+ {
+ /*
+ * Allocate additional elements; start with 16 elements, then
+ * double the size until 1024 elements, then add 1024 elements
+ * thereafter...
+ */
+
+ void **temp; /* New array elements */
+ int count; /* New allocation count */
+
+
+ if (a->alloc_elements == 0)
+ {
+ count = 16;
+ temp = malloc(count * sizeof(void *));
+ }
+ else
+ {
+ if (a->alloc_elements < 1024)
+ count = a->alloc_elements * 2;
+ else
+ count = a->alloc_elements + 1024;
+
+ temp = realloc(a->elements, count * sizeof(void *));
+ }
+
+ DEBUG_printf(("cupsArrayAdd: count=%d\n", count));
+
+ if (!temp)
+ {
+ DEBUG_puts("cupsAddAdd: allocation failed, returning 0");
+ return (0);
+ }
+
+ a->alloc_elements = count;
+ a->elements = temp;
+ }
+
+ /*
+ * Find the insertion point for the new element; if there is no
+ * compare function or elements, just add it to the end...
+ */
+
+ if (!a->num_elements || !a->compare)
+ {
+ /*
+ * Append to the end...
+ */
+
+ current = a->num_elements;
+ }
+ else
+ {
+ /*
+ * Do a binary search for the insertion point...
+ */
+
+ current = cups_find(a, e, a->insert, &diff);
+
+ if (diff > 0)
+ current ++;
+ }
+
+ /*
+ * Insert or append the element...
+ */
+
+ if (current < a->num_elements)
+ {
+ /*
+ * Shift other elements to the right...
+ */
+
+ memmove(a->elements + current + 1, a->elements + current,
+ (a->num_elements - current) * sizeof(void *));
+
+ if (a->current >= current)
+ a->current ++;
+
+ for (i = 0; i < a->num_saved; i ++)
+ if (a->saved[i] >= current)
+ a->saved[i] ++;
+
+ DEBUG_printf(("cupsArrayAdd: insert element at index %d...\n", current));
+ }
+#ifdef DEBUG
+ else
+ printf("cupsArrayAdd: append element at %d...\n", current);
+#endif /* DEBUG */
+
+ a->elements[current] = e;
+ a->num_elements ++;
+ a->insert = current;
+
+#ifdef DEBUG
+ for (current = 0; current < a->num_elements; current ++)
+ printf("cupsArrayAdd: a->elements[%d]=%p\n", current, a->elements[current]);
+#endif /* DEBUG */
+
+ DEBUG_puts("cupsArrayAdd: returning 1");
+
+ return (1);
+}
+
+
+/*
+ * 'cupsArrayClear()' - Clear the array.
+ */
+
+void
+cupsArrayClear(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return;
+
+ /*
+ * Set the number of elements to 0; we don't actually free the memory
+ * here - that is done in cupsArrayDelete()...
+ */
+
+ a->num_elements = 0;
+ a->current = -1;
+ a->insert = -1;
+ a->num_saved = 0;
+}
+
+
+/*
+ * 'cupsArrayCount()' - Get the number of elements in the array.
+ */
+
+int /* O - Number of elements */
+cupsArrayCount(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (0);
+
+ /*
+ * Return the number of elements...
+ */
+
+ return (a->num_elements);
+}
+
+
+/*
+ * 'cupsArrayCurrent()' - Return the current element in the array.
+ */
+
+void * /* O - Element */
+cupsArrayCurrent(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the current element...
+ */
+
+ if (a->current >= 0 && a->current < a->num_elements)
+ return (a->elements[a->current]);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cupsArrayDelete()' - Free all memory used by the array.
+ */
+
+void
+cupsArrayDelete(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return;
+
+ /*
+ * Free the array of element pointers - the caller is responsible
+ * for freeing the elements themselves...
+ */
+
+ if (a->alloc_elements)
+ free(a->elements);
+
+ free(a);
+}
+
+
+/*
+ * 'cupsArrayDup()' - Duplicate the array.
+ */
+
+cups_array_t * /* O - Duplicate array */
+cupsArrayDup(cups_array_t *a) /* I - Array */
+{
+ cups_array_t *da; /* Duplicate array */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Allocate memory for the array...
+ */
+
+ da = calloc(1, sizeof(cups_array_t));
+ if (!da)
+ return (NULL);
+
+ da->compare = a->compare;
+ da->data = a->data;
+ da->current = a->current;
+ da->insert = a->insert;
+ da->num_saved = a->num_saved;
+
+ memcpy(da->saved, a->saved, sizeof(a->saved));
+
+ if (a->num_elements)
+ {
+ /*
+ * Allocate memory for the elements...
+ */
+
+ da->elements = malloc(a->num_elements * sizeof(void *));
+ if (!da->elements)
+ {
+ free(da);
+ return (NULL);
+ }
+
+ /*
+ * Copy the element pointers...
+ */
+
+ memcpy(da->elements, a->elements, a->num_elements * sizeof(void *));
+ da->num_elements = a->num_elements;
+ da->alloc_elements = a->num_elements;
+ }
+
+ /*
+ * Return the new array...
+ */
+
+ return (da);
+}
+
+
+/*
+ * 'cupsArrayFind()' - Find an element in the array.
+ */
+
+void * /* O - Element found or NULL */
+cupsArrayFind(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ int current, /* Current element */
+ diff; /* Difference */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!a || !e)
+ return (NULL);
+
+ /*
+ * See if we have any elements...
+ */
+
+ if (!a->num_elements)
+ return (NULL);
+
+ /*
+ * Yes, look for a match...
+ */
+
+ current = cups_find(a, e, a->current, &diff);
+ if (!diff)
+ {
+ /*
+ * Found a match...
+ */
+
+ a->current = current;
+
+ return (a->elements[current]);
+ }
+ else
+ {
+ /*
+ * No match...
+ */
+
+ a->current = -1;
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'cupsArrayFirst()' - Get the first element in the array.
+ */
+
+void * /* O - First element or NULL */
+cupsArrayFirst(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the first element...
+ */
+
+ a->current = 0;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayIndex()' - Get the N-th element in the array.
+ */
+
+void * /* O - N-th element or NULL */
+cupsArrayIndex(cups_array_t *a, /* I - Array */
+ int n) /* I - Index into array, starting at 0 */
+{
+ if (!a)
+ return (NULL);
+
+ a->current = n;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayLast()' - Get the last element in the array.
+ */
+
+void * /* O - Last element or NULL */
+cupsArrayLast(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the last element...
+ */
+
+ a->current = a->num_elements - 1;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayNew()' - Create a new array.
+ */
+
+cups_array_t * /* O - Array */
+cupsArrayNew(cups_array_func_t f, /* I - Comparison function */
+ void *d) /* I - User data */
+{
+ cups_array_t *a; /* Array */
+
+
+ /*
+ * Allocate memory for the array...
+ */
+
+ a = calloc(1, sizeof(cups_array_t));
+ if (!a)
+ return (NULL);
+
+ a->compare = f;
+ a->data = d;
+ a->current = -1;
+ a->insert = -1;
+ a->num_saved = 0;
+
+ return (a);
+}
+
+
+/*
+ * 'cupsArrayNext()' - Get the next element in the array.
+ */
+
+void * /* O - Next element or NULL */
+cupsArrayNext(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the next element...
+ */
+
+ if (a->current < a->num_elements)
+ a->current ++;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayPrev()' - Get the previous element in the array.
+ */
+
+void * /* O - Previous element or NULL */
+cupsArrayPrev(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the previous element...
+ */
+
+ if (a->current >= 0)
+ a->current --;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayRemove()' - Remove an element from the array.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsArrayRemove(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ int i, /* Looping var */
+ current, /* Current element */
+ diff; /* Difference */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!a || !e)
+ return (0);
+
+ /*
+ * See if the element is in the array...
+ */
+
+ if (!a->num_elements)
+ return (0);
+
+ current = cups_find(a, e, a->current, &diff);
+ if (diff)
+ return (0);
+
+ /*
+ * Yes, now remove it...
+ */
+
+ a->num_elements --;
+
+ if (current < a->num_elements)
+ memmove(a->elements + current, a->elements + current + 1,
+ (a->num_elements - current) * sizeof(void *));
+
+ if (current <= a->current)
+ a->current --;
+
+ if (current <= a->insert)
+ a->insert --;
+
+ for (i = 0; i < a->num_saved; i ++)
+ if (current <= a->saved[i])
+ a->saved[i] --;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave.
+ */
+
+void * /* O - New current element */
+cupsArrayRestore(cups_array_t *a) /* I - Array */
+{
+ if (!a)
+ return (NULL);
+
+ if (a->num_saved <= 0)
+ return (NULL);
+
+ a->num_saved --;
+ a->current = a->saved[a->num_saved];
+
+ if (a->current >= 0 && a->current < a->num_elements)
+ return (a->elements[a->current]);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore.
+ *
+ * The save/restore stack is guaranteed to be at least 32 elements deep.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsArraySave(cups_array_t *a) /* I - Array */
+{
+ if (!a)
+ return (0);
+
+ if (a->num_saved >= _CUPS_MAXSAVE)
+ return (0);
+
+ a->saved[a->num_saved] = a->current;
+ a->num_saved ++;
+
+ return (1);
+}
+
+
+/*
+ * 'cups_find()' - Find an element in the array...
+ */
+
+static int /* O - Index of match */
+cups_find(cups_array_t *a, /* I - Array */
+ void *e, /* I - Element */
+ int prev, /* I - Previous index */
+ int *rdiff) /* O - Difference of match */
+{
+ int left, /* Left side of search */
+ right, /* Right side of search */
+ current, /* Current element */
+ diff; /* Comparison with current element */
+
+
+ DEBUG_printf(("cups_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a, e, prev,
+ rdiff));
+
+ if (a->compare)
+ {
+ /*
+ * Do a binary search for the element...
+ */
+
+ DEBUG_puts("cups_find: binary search");
+
+ if (prev >= 0 && prev < a->num_elements)
+ {
+ /*
+ * Start search on either side of previous...
+ */
+
+ if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 ||
+ (diff < 0 && prev == 0) ||
+ (diff > 0 && prev == (a->num_elements - 1)))
+ {
+ /*
+ * Exact or edge match, return it!
+ */
+
+ DEBUG_printf(("cups_find: Returning %d, diff=%d\n", prev, diff));
+
+ *rdiff = diff;
+
+ return (prev);
+ }
+ else if (diff < 0)
+ {
+ /*
+ * Start with previous on right side...
+ */
+
+ left = 0;
+ right = prev;
+ }
+ else
+ {
+ /*
+ * Start wih previous on left side...
+ */
+
+ left = prev;
+ right = a->num_elements - 1;
+ }
+ }
+ else
+ {
+ /*
+ * Start search in the middle...
+ */
+
+ left = 0;
+ right = a->num_elements - 1;
+ }
+
+ do
+ {
+ current = (left + right) / 2;
+ diff = (*(a->compare))(e, a->elements[current], a->data);
+
+ DEBUG_printf(("cups_find: left=%d, right=%d, current=%d, diff=%d\n",
+ left, right, current, diff));
+
+ if (diff == 0)
+ break;
+ else if (diff < 0)
+ right = current;
+ else
+ left = current;
+ }
+ while ((right - left) > 1);
+
+ if (diff != 0)
+ {
+ /*
+ * Check the last 1 or 2 elements...
+ */
+
+ if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0)
+ current = left;
+ else
+ {
+ diff = (*(a->compare))(e, a->elements[right], a->data);
+ current = right;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Do a linear pointer search...
+ */
+
+ DEBUG_puts("cups_find: linear search");
+
+ diff = 0;
+
+ for (current = 0; current < a->num_elements; current ++)
+ if (a->elements[current] == e)
+ break;
+ }
+
+ /*
+ * Return the closest element and the difference...
+ */
+
+ DEBUG_printf(("cups_find: Returning %d, diff=%d\n", current, diff));
+
+ *rdiff = diff;
+
+ return (current);
+}
+
+
+/*
+ * End of "$Id: array.c 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cups/array.h b/cups/array.h
new file mode 100644
index 000000000..1043121e2
--- /dev/null
+++ b/cups/array.h
@@ -0,0 +1,83 @@
+/*
+ * "$Id: array.h 4921 2006-01-12 21:26:26Z mike $"
+ *
+ * Sorted array definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_ARRAY_H_
+# define _CUPS_ARRAY_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct _cups_array_s cups_array_t;
+ /**** CUPS array type ****/
+typedef int (*cups_array_func_t)(void *first, void *second, void *data);
+ /**** Array comparison function ****/
+
+/*
+ * Functions...
+ */
+
+extern int cupsArrayAdd(cups_array_t *a, void *e);
+extern void cupsArrayClear(cups_array_t *a);
+extern int cupsArrayCount(cups_array_t *a);
+extern void *cupsArrayCurrent(cups_array_t *a);
+extern void cupsArrayDelete(cups_array_t *a);
+extern cups_array_t *cupsArrayDup(cups_array_t *a);
+extern void *cupsArrayFind(cups_array_t *a, void *e);
+extern void *cupsArrayFirst(cups_array_t *a);
+extern void *cupsArrayIndex(cups_array_t *a, int n);
+extern void *cupsArrayLast(cups_array_t *a);
+extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d);
+extern void *cupsArrayNext(cups_array_t *a);
+extern void *cupsArrayPrev(cups_array_t *a);
+extern int cupsArrayRemove(cups_array_t *a, void *e);
+extern void *cupsArrayRestore(cups_array_t *a);
+extern int cupsArraySave(cups_array_t *a);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_ARRAY_H_ */
+
+/*
+ * End of "$Id: array.h 4921 2006-01-12 21:26:26Z mike $".
+ */
diff --git a/cups/attr.c b/cups/attr.c
new file mode 100644
index 000000000..36f911d0b
--- /dev/null
+++ b/cups/attr.c
@@ -0,0 +1,184 @@
+/*
+ * "$Id: attr.c 4785 2005-10-13 19:39:05Z mike $"
+ *
+ * PPD model-specific attribute routines for the Common UNIX Printing System
+ * (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * ppdFindAttr() - Find the first matching attribute...
+ * ppdFindNextAttr() - Find the next matching attribute...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ppd.h"
+#include "debug.h"
+#include "string.h"
+#include
+
+
+/*
+ * Private function...
+ */
+
+extern int _ppd_attr_compare(ppd_attr_t **a, ppd_attr_t **b);
+
+
+/*
+ * 'ppdFindAttr()' - Find the first matching attribute...
+ *
+ * @since CUPS 1.1.19@
+ */
+
+ppd_attr_t * /* O - Attribute or NULL if not found */
+ppdFindAttr(ppd_file_t *ppd, /* I - PPD file data */
+ const char *name, /* I - Attribute name */
+ const char *spec) /* I - Specifier string or NULL */
+{
+ ppd_attr_t key, /* Search key */
+ *keyptr, /* Pointer to key */
+ **match; /* Matching attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (ppd == NULL || name == NULL || ppd->num_attrs == 0)
+ return (NULL);
+
+ /*
+ * Do a binary search for a matching attribute...
+ */
+
+ memset(&key, 0, sizeof(key));
+ strncpy(key.name, name, sizeof(key.name) - 1);
+ if (spec)
+ strncpy(key.spec, spec, sizeof(key.spec) - 1);
+
+ keyptr = &key;
+
+ match = bsearch(&keyptr, ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
+ (int (*)(const void *, const void *))_ppd_attr_compare);
+
+ if (match == NULL)
+ {
+ /*
+ * No match!
+ */
+
+ ppd->cur_attr = -1;
+ return (NULL);
+ }
+
+ if (match > ppd->attrs && spec == NULL)
+ {
+ /*
+ * Find the first attribute with the same name...
+ */
+
+ while (match > ppd->attrs)
+ {
+ if (strcmp(match[-1]->name, name) != 0)
+ break;
+
+ match --;
+ }
+ }
+
+ /*
+ * Save the current attribute and return its value...
+ */
+
+ ppd->cur_attr = match - ppd->attrs;
+
+ return (*match);
+}
+
+
+/*
+ * 'ppdFindNextAttr()' - Find the next matching attribute...
+ *
+ * @since CUPS 1.1.19@
+ */
+
+ppd_attr_t * /* O - Attribute or NULL if not found */
+ppdFindNextAttr(ppd_file_t *ppd, /* I - PPD file data */
+ const char *name, /* I - Attribute name */
+ const char *spec) /* I - Specifier string or NULL */
+{
+ ppd_attr_t **match; /* Matching attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (ppd == NULL || name == NULL || ppd->num_attrs == 0 || ppd->cur_attr < 0)
+ return (NULL);
+
+ /*
+ * See if there are more attributes to return...
+ */
+
+ ppd->cur_attr ++;
+
+ if (ppd->cur_attr >= ppd->num_attrs)
+ {
+ /*
+ * Nope...
+ */
+
+ ppd->cur_attr = -1;
+ return (NULL);
+ }
+
+ /*
+ * Check the next attribute to see if it is a match...
+ */
+
+ match = ppd->attrs + ppd->cur_attr;
+
+ if (strcmp((*match)->name, name) != 0 ||
+ (spec != NULL && strcmp((*match)->spec, spec) != 0))
+ {
+ /*
+ * Nope...
+ */
+
+ ppd->cur_attr = -1;
+ return (NULL);
+ }
+
+ /*
+ * Return the next attribute's value...
+ */
+
+ return (*match);
+}
+
+
+/*
+ * End of "$Id: attr.c 4785 2005-10-13 19:39:05Z mike $".
+ */
diff --git a/cups/auth.c b/cups/auth.c
new file mode 100644
index 000000000..681728fb3
--- /dev/null
+++ b/cups/auth.c
@@ -0,0 +1,249 @@
+/*
+ * "$Id: auth.c 4918 2006-01-12 05:14:40Z mike $"
+ *
+ * Authentication functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsDoAuthentication() - Authenticate a request.
+ * cups_local_auth() - Get the local authorization certificate if
+ * available/applicable...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "globals.h"
+#include "debug.h"
+#include
+#include
+#include
+#include
+#include
+#if defined(WIN32) || defined(__EMX__)
+# include
+#else
+# include
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_local_auth(http_t *http);
+
+
+/*
+ * 'cupsDoAuthentication()' - Authenticate a request.
+ *
+ * This function should be called in response to a HTTP_UNAUTHORIZED
+ * status, prior to resubmitting your request.
+ *
+ * @since CUPS 1.1.20@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsDoAuthentication(http_t *http, /* I - HTTP connection to server */
+ const char *method,/* I - Request method (GET, POST, PUT) */
+ const char *resource)
+ /* I - Resource path */
+{
+ const char *password; /* Password string */
+ char prompt[1024], /* Prompt for user */
+ realm[HTTP_MAX_VALUE], /* realm="xyz" string */
+ nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */
+ encode[512]; /* Encoded username:password */
+
+
+ DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")\n",
+ http, method, resource));
+ DEBUG_printf(("cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"\n",
+ http->digest_tries, http->userpass));
+
+ /*
+ * Clear the current authentication string...
+ */
+
+ http->authstring[0] = '\0';
+
+ /*
+ * See if we can do local authentication...
+ */
+
+ if (!cups_local_auth(http))
+ {
+ DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", http->authstring));
+ return (0);
+ }
+
+ /*
+ * Nope, see if we should retry the current username:password...
+ */
+
+ if (http->digest_tries > 1 || !http->userpass[0])
+ {
+ /*
+ * Nope - get a new password from the user...
+ */
+
+ snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(),
+ http->hostname);
+
+ http->digest_tries = strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
+ "Digest", 5) != 0;
+ http->userpass[0] = '\0';
+
+ if ((password = cupsGetPassword(prompt)) == NULL)
+ return (-1);
+
+ if (!password[0])
+ return (-1);
+
+ snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(),
+ password);
+ }
+ else if (http->status == HTTP_UNAUTHORIZED)
+ http->digest_tries ++;
+
+ /*
+ * Got a password; encode it for the server...
+ */
+
+ if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6))
+ {
+ /*
+ * Basic authentication...
+ */
+
+ httpEncode64_2(encode, sizeof(encode), http->userpass,
+ strlen(http->userpass));
+ snprintf(http->authstring, sizeof(http->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, strchr(http->userpass, ':') + 1, encode);
+ httpMD5Final(nonce, method, resource, encode);
+ snprintf(http->authstring, sizeof(http->authstring),
+ "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
+ "uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce,
+ resource, encode);
+ }
+
+ DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", http->authstring));
+
+ return (0);
+}
+
+
+/*
+ * 'cups_local_auth()' - Get the local authorization certificate if
+ * available/applicable...
+ */
+
+static int /* O - 0 if available, -1 if not */
+cups_local_auth(http_t *http) /* I - HTTP connection to server */
+{
+#if defined(WIN32) || defined(__EMX__)
+ /*
+ * Currently WIN32 and OS-2 do not support the CUPS server...
+ */
+
+ return (-1);
+#else
+ int pid; /* Current process ID */
+ FILE *fp; /* Certificate file */
+ char filename[1024], /* Certificate filename */
+ certificate[33]; /* Certificate string */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ DEBUG_printf(("cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"\n",
+ http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname));
+
+ /*
+ * See if we are accessing localhost...
+ */
+
+ if (!httpAddrLocalhost(http->hostaddr) &&
+ strcasecmp(http->hostname, "localhost") != 0)
+ {
+ DEBUG_puts("cups_local_auth: Not a local connection!");
+ return (-1);
+ }
+
+ /*
+ * Try opening a certificate file for this PID. If that fails,
+ * try the root certificate...
+ */
+
+ pid = getpid();
+ snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid);
+ if ((fp = fopen(filename, "r")) == NULL && pid > 0)
+ {
+ DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n",
+ filename, strerror(errno)));
+
+ snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir);
+ fp = fopen(filename, "r");
+ }
+
+ if (fp == NULL)
+ {
+ DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n",
+ filename, strerror(errno)));
+ return (-1);
+ }
+
+ /*
+ * Read the certificate from the file...
+ */
+
+ fgets(certificate, sizeof(certificate), fp);
+ fclose(fp);
+
+ /*
+ * Set the authorization string and return...
+ */
+
+ snprintf(http->authstring, sizeof(http->authstring), "Local %s", certificate);
+
+ DEBUG_printf(("cups_local_auth: Returning authstring = \"%s\"\n",
+ http->authstring));
+
+ return (0);
+#endif /* WIN32 || __EMX__ */
+}
+
+
+/*
+ * End of "$Id: auth.c 4918 2006-01-12 05:14:40Z mike $".
+ */
diff --git a/cups/backchannel.c b/cups/backchannel.c
new file mode 100644
index 000000000..3cb3a0def
--- /dev/null
+++ b/cups/backchannel.c
@@ -0,0 +1,201 @@
+/*
+ * "$Id: backchannel.c 4828 2005-11-11 12:53:38Z mike $"
+ *
+ * Backchannel functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsBackChannelRead() - Read data from the backchannel.
+ * cupsBackChannelWrite() - Write data to the backchannel.
+ * cups_setup() - Setup select()
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include
+#ifdef WIN32
+# include
+# include
+#else
+# include
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+static void cups_setup(fd_set *set, struct timeval *tval,
+ double timeout);
+
+
+/*
+ * 'cupsBackChannelRead()' - Read data from the backchannel.
+ *
+ * Reads up to "bytes" bytes from the backchannel. The "timeout"
+ * parameter controls how many seconds to wait for the data - use
+ * 0.0 to return immediately if there is no data, -1.0 to wait
+ * for data indefinitely.
+ *
+ * @since CUPS 1.2@
+ */
+
+int /* O - Bytes read or -1 on error */
+cupsBackchannelRead(char *buffer, /* I - Buffer to read */
+ int bytes, /* I - Bytes to read */
+ double timeout) /* I - Timeout in seconds */
+{
+ fd_set input; /* Input set */
+ struct timeval tval; /* Timeout value */
+ int status; /* Select status */
+
+
+ /*
+ * Wait for input ready.
+ */
+
+ do
+ {
+ cups_setup(&input, &tval, timeout);
+
+ if (timeout < 0.0)
+ status = select(4, &input, NULL, NULL, NULL);
+ else
+ status = select(4, &input, NULL, NULL, &tval);
+ }
+ while (status < 0 && errno != EINTR);
+
+ if (status < 0)
+ return (-1); /* Timeout! */
+
+ /*
+ * Read bytes from the pipe...
+ */
+
+ return (read(3, buffer, bytes));
+}
+
+
+/*
+ * 'cupsBackChannelWrite()' - Write data to the backchannel.
+ *
+ * Writes "bytes" bytes to the backchannel. The "timeout" parameter
+ * controls how many seconds to wait for the data to be written - use
+ * 0.0 to return immediately if the data cannot be written, -1.0 to wait
+ * indefinitely.
+ *
+ * @since CUPS 1.2@
+ */
+
+int /* O - Bytes written or -1 on error */
+cupsBackchannelWrite(
+ const char *buffer, /* I - Buffer to write */
+ int bytes, /* I - Bytes to write */
+ double timeout) /* I - Timeout in seconds */
+{
+ fd_set output; /* Output set */
+ struct timeval tval; /* Timeout value */
+ int status; /* Select status */
+ int count, /* Current bytes */
+ total; /* Total bytes */
+
+
+ /*
+ * Write all bytes...
+ */
+
+ total = 0;
+
+ while (total < bytes)
+ {
+ /*
+ * Wait for write-ready...
+ */
+
+ do
+ {
+ cups_setup(&output, &tval, timeout);
+
+ if (timeout < 0.0)
+ status = select(4, NULL, &output, NULL, NULL);
+ else
+ status = select(4, NULL, &output, NULL, &tval);
+ }
+ while (status < 0 && errno != EINTR);
+
+ if (status < 0)
+ return (-1); /* Timeout! */
+
+ /*
+ * Write bytes to the pipe...
+ */
+
+ count = write(3, buffer, bytes - total);
+
+ if (count < 0)
+ {
+ /*
+ * Write error - abort on fatal errors...
+ */
+
+ if (errno != EINTR && errno != EAGAIN)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Write succeeded, update buffer pointer and total count...
+ */
+
+ buffer += count;
+ total += count;
+ }
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * 'cups_setup()' - Setup select()
+ */
+
+static void
+cups_setup(fd_set *set, /* I - Set for select() */
+ struct timeval *tval, /* I - Timer value */
+ double timeout) /* I - Timeout in seconds */
+{
+ tval->tv_sec = (int)timeout;
+ tval->tv_usec = (int)(1000000.0 * (timeout - tval->tv_sec));
+
+ FD_ZERO(set);
+ FD_SET(3, set);
+}
+
+
+/*
+ * End of "$Id: backchannel.c 4828 2005-11-11 12:53:38Z mike $".
+ */
diff --git a/cups/backend.h b/cups/backend.h
new file mode 100644
index 000000000..199780a05
--- /dev/null
+++ b/cups/backend.h
@@ -0,0 +1,50 @@
+/*
+ * "$Id: backend.h 4703 2005-09-26 19:33:58Z mike $"
+ *
+ * Backend definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_BACKEND_H_
+# define _CUPS_BACKEND_H_
+
+
+/*
+ * Constants...
+ */
+
+typedef enum cups_backend_e /**** Backend exit codes ****/
+{
+ CUPS_BACKEND_OK = 0, /* Job completed successfully */
+ CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */
+ CUPS_BACKEND_CANCEL = 2, /* Job failed, cancel job */
+ CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */
+ CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */
+ CUPS_BACKEND_AUTH_REQUIRED = 5 /* Job failed, authentication required */
+} cups_backend_t;
+
+
+#endif /* !_CUPS_BACKEND_H_ */
+
+/*
+ * End of "$Id: backend.h 4703 2005-09-26 19:33:58Z mike $".
+ */
diff --git a/cups/cups.h b/cups/cups.h
new file mode 100644
index 000000000..84a0f3793
--- /dev/null
+++ b/cups/cups.h
@@ -0,0 +1,237 @@
+/*
+ * "$Id: cups.h 4918 2006-01-12 05:14:40Z mike $"
+ *
+ * API definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_CUPS_H_
+# define _CUPS_CUPS_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "ipp.h"
+# include "ppd.h"
+
+/*
+ * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get
+ * an error at compile-time.
+ */
+
+# if defined(__GNUC__) && __GNUC__ > 2
+# define _CUPS_DEPRECATED __attribute__ ((__deprecated__))
+# else
+# define _CUPS_DEPRECATED
+# endif /* __GNUC__ && __GNUC__ > 2 */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define CUPS_VERSION 1.0190
+# define CUPS_VERSION_MAJOR 1
+# define CUPS_VERSION_MINOR 2
+# define CUPS_VERSION_PATCH -10
+# define CUPS_DATE_ANY -1
+
+
+/*
+ * Types and structures...
+ */
+
+typedef unsigned cups_ptype_t; /**** Printer Type/Capability Bits ****/
+enum cups_ptype_e /* 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_FAX = 0x40000, /* Fax queue */
+ CUPS_PRINTER_REJECTING = 0x80000, /* Printer is rejecting jobs */
+ CUPS_PRINTER_DELETE = 0x100000, /* Delete printer @since CUPS 1.2@ */
+ CUPS_PRINTER_NOT_SHARED = 0x200000, /* Printer is not shared @since CUPS 1.2@ */
+ CUPS_PRINTER_AUTHENTICATED = 0x400000,/* Printer requires authentication @since CUPS 1.2@ */
+ CUPS_PRINTER_OPTIONS = 0x66fffc /* ~(CLASS | REMOTE | IMPLICIT) */
+};
+
+typedef const char *(*cups_password_cb_t)(const char *);
+
+typedef struct cups_option_s /**** Printer Options ****/
+{
+ char *name; /* Name of option */
+ char *value; /* Value of option */
+} cups_option_t;
+
+typedef struct cups_dest_s /**** 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 cups_job_s /**** 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) _CUPS_DEPRECATED;
+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) _CUPS_DEPRECATED;
+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) _CUPS_DEPRECATED;
+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(cups_password_cb_t cb);
+extern void cupsSetServer(const char *server);
+extern void cupsSetUser(const char *user);
+extern const char *cupsUser(void);
+
+/**** New in CUPS 1.1.20 ****/
+extern int cupsDoAuthentication(http_t *http, const char *method,
+ const char *resource);
+extern http_status_t cupsGetFile(http_t *http, const char *resource,
+ const char *filename);
+extern http_status_t cupsGetFd(http_t *http, const char *resource, int fd);
+extern http_status_t cupsPutFile(http_t *http, const char *resource,
+ const char *filename);
+extern http_status_t cupsPutFd(http_t *http, const char *resource, int fd);
+
+/**** New in CUPS 1.1.21 ****/
+extern const char *cupsGetDefault2(http_t *http);
+extern int cupsGetDests2(http_t *http, cups_dest_t **dests);
+extern int cupsGetJobs2(http_t *http, cups_job_t **jobs,
+ const char *dest, int myjobs,
+ int completed);
+extern const char *cupsGetPPD2(http_t *http, const char *printer);
+extern int cupsPrintFile2(http_t *http, const char *printer,
+ const char *filename,
+ const char *title, int num_options,
+ cups_option_t *options);
+extern int cupsPrintFiles2(http_t *http, const char *printer,
+ int num_files, const char **files,
+ const char *title, int num_options,
+ cups_option_t *options);
+extern int cupsSetDests2(http_t *http, int num_dests,
+ cups_dest_t *dests);
+
+/**** New in CUPS 1.2 ****/
+extern int cupsBackchannelRead(char *buffer, int bytes, double timeout);
+extern int cupsBackchannelWrite(const char *buffer, int bytes,
+ double timeout);
+extern void cupsEncodeOptions2(ipp_t *ipp, int num_options,
+ cups_option_t *options,
+ ipp_tag_t group_tag);
+extern const char *cupsLastErrorString(void);
+extern cups_file_t *cupsTempFile2(char *filename, int len);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_CUPS_H_ */
+
+/*
+ * End of "$Id: cups.h 4918 2006-01-12 05:14:40Z mike $".
+ */
diff --git a/cups/debug.h b/cups/debug.h
new file mode 100644
index 000000000..65b1fa224
--- /dev/null
+++ b/cups/debug.h
@@ -0,0 +1,59 @@
+/*
+ * "$Id: debug.h 4493 2005-02-18 02:09:53Z mike $"
+ *
+ * Debugging macros for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#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: debug.h 4493 2005-02-18 02:09:53Z mike $".
+ */
diff --git a/cups/dest.c b/cups/dest.c
new file mode 100644
index 000000000..042e7b54b
--- /dev/null
+++ b/cups/dest.c
@@ -0,0 +1,865 @@
+/*
+ * "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $"
+ *
+ * User-defined destination (and option) support for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1997-2006 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * 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 from the default server.
+ * cupsGetDests2() - Get the list of destinations from the specified server.
+ * cupsSetDests() - Set the list of destinations for the default server.
+ * cupsSetDests2() - Set the list of destinations for the specified server.
+ * cups_get_dests() - Get destinations from a file.
+ * cups_get_sdests() - Get destinations from a server.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "globals.h"
+#include
+#include
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_get_dests(const char *filename, int num_dests,
+ cups_dest_t **dests);
+static int cups_get_sdests(http_t *http, ipp_op_t op, int num_dests,
+ cups_dest_t **dests);
+
+
+/*
+ * 'cupsAddDest()' - Add a destination to the list of destinations.
+ *
+ * Use the cupsSaveDests() function to save the updated list of destinations
+ * to the user's lpoptions file.
+ */
+
+int /* O - New number of destinations */
+cupsAddDest(const char *name, /* I - Name of destination */
+ const char *instance, /* I - Instance of destination or NULL for none/primary */
+ 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.
+ *
+ * Use the cupsGetDests() or cupsGetDests2() functions to get a
+ * list of supported destinations for the current user.
+ */
+
+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 from the default server.
+ */
+
+int /* O - Number of destinations */
+cupsGetDests(cups_dest_t **dests) /* O - Destinations */
+{
+ int num_dests; /* Number of destinations */
+ http_t *http; /* HTTP connection */
+
+
+ /*
+ * Connect to the CUPS server and get the destination list and options...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ num_dests = cupsGetDests2(http, dests);
+
+ if (http)
+ httpClose(http);
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cupsGetDests2()' - Get the list of destinations from the specified server.
+ *
+ * @since CUPS 1.1.21@
+ */
+
+int /* O - Number of destinations */
+cupsGetDests2(http_t *http, /* I - HTTP connection */
+ cups_dest_t **dests) /* O - Destinations */
+{
+ int i; /* Looping var */
+ int num_dests; /* Number of destinations */
+ 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 */
+ int num_reals; /* Number of real queues */
+ cups_dest_t *reals; /* Real queues */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (!http || !dests)
+ return (0);
+
+ /*
+ * Initialize destination array...
+ */
+
+ num_dests = 0;
+ *dests = (cups_dest_t *)0;
+
+ /*
+ * Grab the printers and classes...
+ */
+
+ num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, num_dests, dests);
+ num_dests = cups_get_sdests(http, CUPS_GET_CLASSES, num_dests, dests);
+
+ /*
+ * Make a copy of the "real" queues for a later sanity check...
+ */
+
+ if (num_dests > 0)
+ {
+ num_reals = num_dests;
+ reals = calloc(num_reals, sizeof(cups_dest_t));
+
+ if (reals)
+ memcpy(reals, *dests, num_reals * sizeof(cups_dest_t));
+ else
+ num_reals = 0;
+ }
+ else
+ {
+ num_reals = 0;
+ reals = NULL;
+ }
+
+ /*
+ * Grab the default destination...
+ */
+
+ if ((defprinter = cupsGetDefault2(http)) != NULL)
+ {
+ /*
+ * Grab printer and instance name...
+ */
+
+ strlcpy(name, defprinter, sizeof(name));
+
+ 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;
+ }
+ else
+ {
+ /*
+ * This initialization of "instance" is unnecessary, but avoids a
+ * compiler warning...
+ */
+
+ instance = NULL;
+ }
+
+ /*
+ * Load the /etc/cups/lpoptions and ~/.lpoptions files...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+ num_dests = cups_get_dests(filename, num_dests, dests);
+
+ if ((home = getenv("HOME")) != NULL)
+ {
+ snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
+ num_dests = cups_get_dests(filename, num_dests, dests);
+ }
+
+ /*
+ * Validate the current default destination - this prevents old
+ * Default lines in /etc/cups/lpoptions and ~/.lpoptions from
+ * pointing to a non-existent printer or class...
+ */
+
+ if (num_reals)
+ {
+ /*
+ * See if we have a default printer...
+ */
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL)
+ {
+ /*
+ * Have a default; see if it is real...
+ */
+
+ dest = cupsGetDest(dest->name, NULL, num_reals, reals);
+ }
+
+ /*
+ * If dest is NULL, then no default (that exists) is set, so we
+ * need to set a default if one exists...
+ */
+
+ if (dest == NULL && defprinter != NULL)
+ {
+ for (i = 0; i < num_dests; i ++)
+ (*dests)[i].is_default = 0;
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
+ dest->is_default = 1;
+ }
+
+ /*
+ * Free memory...
+ */
+
+ free(reals);
+ }
+
+ /*
+ * Return the number of destinations...
+ */
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cupsSetDests()' - Save the list of destinations for the default server.
+ *
+ * This function saves the destinations to /etc/cups/lpoptions when run
+ * as root and ~/.lpoptions when run as a normal user.
+ */
+
+void
+cupsSetDests(int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests) /* I - Destinations */
+{
+ http_t *http; /* HTTP connection */
+
+
+ /*
+ * Connect to the CUPS server and save the destination list and options...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ cupsSetDests2(http, num_dests, dests);
+
+ if (http)
+ httpClose(http);
+}
+
+
+/*
+ * 'cupsSetDests2()' - Save the list of destinations for the specified server.
+ *
+ * This function saves the destinations to /etc/cups/lpoptions when run
+ * as root and ~/.lpoptions when run as a normal user.
+ *
+ * @since CUPS 1.1.21@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsSetDests2(http_t *http, /* I - HTTP connection */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests) /* I - Destinations */
+{
+ int i, j; /* Looping vars */
+ int wrote; /* Wrote definition? */
+ 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 */
+ int num_temps; /* Number of temporary destinations */
+ cups_dest_t *temps, /* Temporary destinations */
+ *temp; /* Current temporary dest */
+ const char *val; /* Value of temporary option */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (!http || !num_dests || !dests)
+ return (-1);
+
+ /*
+ * Get the server destinations...
+ */
+
+ num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps);
+ num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps);
+
+ /*
+ * Figure out which file to write to...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+
+#ifndef WIN32
+ if (getuid())
+ {
+ /*
+ * Merge in server defaults...
+ */
+
+ num_temps = cups_get_dests(filename, num_temps, &temps);
+
+ /*
+ * Point to user defaults...
+ */
+
+ if ((home = getenv("HOME")) != NULL)
+ snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
+ }
+#endif /* !WIN32 */
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ {
+ cupsFreeDests(num_temps, temps);
+ return (-1);
+ }
+
+ /*
+ * 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)
+ {
+ if (dest->is_default)
+ {
+ fprintf(fp, "Default %s", dest->name);
+ if (dest->instance)
+ fprintf(fp, "/%s", dest->instance);
+
+ wrote = 1;
+ }
+ else
+ wrote = 0;
+
+ if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
+ temp = cupsGetDest(dest->name, NULL, num_temps, temps);
+
+ for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
+ {
+ /*
+ * See if the server/global options match these; if so, don't
+ * write 'em.
+ */
+
+ if (temp && (val = cupsGetOption(option->name, temp->num_options,
+ temp->options)) != NULL)
+ {
+ if (strcasecmp(val, option->value) == 0)
+ continue;
+ }
+
+ /*
+ * Options don't match, write to the file...
+ */
+
+ if (!wrote)
+ {
+ fprintf(fp, "Dest %s", dest->name);
+ if (dest->instance)
+ fprintf(fp, "/%s", dest->instance);
+ wrote = 1;
+ }
+
+ 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);
+ }
+
+ if (wrote)
+ fputs("\n", fp);
+ }
+
+ /*
+ * Free the temporary destinations...
+ */
+
+ cupsFreeDests(num_temps, temps);
+
+ /*
+ * Close the file and return...
+ */
+
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * '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] & 255))
+ lineptr = line + 4;
+ else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
+ lineptr = line + 7;
+ else
+ continue;
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ if (!*lineptr)
+ continue;
+
+ name = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
+ lineptr ++;
+
+ if (!*lineptr)
+ continue;
+
+ if (*lineptr == '/')
+ {
+ /*
+ * Found an instance...
+ */
+
+ *lineptr++ = '\0';
+ instance = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+ }
+ else
+ instance = NULL;
+
+ *lineptr++ = '\0';
+
+ /*
+ * See if the primary instance of the destination exists; if not,
+ * ignore this entry and move on...
+ */
+
+ if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
+ continue;
+
+ /*
+ * 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...
+ */
+
+ 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);
+}
+
+
+/*
+ * 'cups_get_sdests()' - Get destinations from a server.
+ */
+
+static int /* O - Number of destinations */
+cups_get_sdests(http_t *http, /* I - HTTP connection */
+ ipp_op_t op, /* I - get-printers or get-classes */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ cups_dest_t *dest; /* Current destination */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *name; /* printer-name attribute */
+ char job_sheets[1024]; /* job-sheets option */
+ static const char * const pattrs[] = /* Attributes we're interested in */
+ {
+ "printer-name",
+ "job-sheets-default"
+ };
+
+
+ /*
+ * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
+ * the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ */
+
+ 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);
+
+ cupsLangFree(language);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ name = NULL;
+
+ strcpy(job_sheets, "");
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-sheets-default") == 0 &&
+ (attr->value_tag == IPP_TAG_KEYWORD ||
+ attr->value_tag == IPP_TAG_NAME))
+ {
+ if (attr->num_values == 2)
+ snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
+ attr->values[0].string.text, attr->values[1].string.text);
+ else
+ strcpy(job_sheets, attr->values[0].string.text);
+ }
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (!name)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ num_dests = cupsAddDest(name, NULL, num_dests, dests);
+
+ if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
+ if (job_sheets[0])
+ dest->num_options = cupsAddOption("job-sheets", job_sheets, 0,
+ &(dest->options));
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Return the count...
+ */
+
+ return (num_dests);
+}
+
+
+/*
+ * End of "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $".
+ */
diff --git a/cups/dir.c b/cups/dir.c
new file mode 100644
index 000000000..e06edea91
--- /dev/null
+++ b/cups/dir.c
@@ -0,0 +1,437 @@
+/*
+ * "$Id$"
+ *
+ * Public directory routines for the Common UNIX Printing System (CUPS).
+ *
+ * This set of APIs abstracts enumeration of directory entries.
+ *
+ * Copyright 1997-2005 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 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * _cups_dir_time() - Convert a FILETIME value to a UNIX time value.
+ * cupsDirClose() - Close a directory.
+ * cupsDirOpen() - Open a directory.
+ * cupsDirRead() - Read the next directory entry.
+ * cupsDirRewind() - Rewind to the start of the directory.
+ * cupsDirClose() - Close a directory.
+ * cupsDirOpen() - Open a directory.
+ * cupsDirRead() - Read the next directory entry.
+ * cupsDirRewind() - Rewind to the start of the directory.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "dir.h"
+#include "string.h"
+#include "debug.h"
+#include